您的位置:首页 > 其它

算法系列15天速成——第十一天 树操作(上)

2011-12-11 00:18 477 查看
最近项目赶的紧,歇了一个星期没写博客了,趁周末继续写这个系列。

先前我们讲的都是“线性结构”,他的特征就是“一个节点最多有一个”前驱“和一个”后继“。那么我们今天讲的树会是怎样的呢?

我们可以对”线性结构“改造一下,变为”一个节点最多有一个"前驱“和”多个后继“。哈哈,这就是我们今天说的”树“。

一: 树

我们思维中的”树“就是一种枝繁叶茂的形象,那么数据结构中的”树“该是怎么样呢?对的,他是一种现实中倒立的树。

View Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ChainTree
{
public class Program
{
static void Main(string[] args)
{
ChainTreeManager manager = new ChainTreeManager();

//插入节点操作
ChainTree<string> tree = CreateRoot();

//插入节点数据
AddNode(tree);

//先序遍历
Console.WriteLine("\n先序结果为: \n");
manager.BinTree_DLR(tree);

//中序遍历
Console.WriteLine("\n中序结果为: \n");
manager.BinTree_LDR(tree);

//后序遍历
Console.WriteLine("\n后序结果为: \n");
manager.BinTree_LRD(tree);

//层次遍历
Console.WriteLine("\n层次结果为: \n");
manager.Length = 100;
manager.BinTree_Level(tree);

Console.WriteLine("\n树的深度为:" + manager.BinTreeLen(tree) + "\n");

Console.ReadLine();

}

#region 生成根节点
/// <summary>
/// 生成根节点
/// </summary>
/// <returns></returns>
static ChainTree<string> CreateRoot()
{
ChainTree<string> tree = new ChainTree<string>();

Console.WriteLine("请输入根节点,方便我们生成树\n");

tree.data = Console.ReadLine();

Console.WriteLine("根节点生成已经生成\n");

return tree;
}
#endregion

#region 插入节点操作
/// <summary>
/// 插入节点操作
/// </summary>
/// <param name="tree"></param>
static ChainTree<string> AddNode(ChainTree<string> tree)
{
ChainTreeManager mananger = new ChainTreeManager();

while (true)
{
ChainTree<string> node = new ChainTree<string>();

Console.WriteLine("请输入要插入节点的数据:\n");

node.data = Console.ReadLine();

Console.WriteLine("请输入要查找的父节点数据:\n");

var parentData = Console.ReadLine();

if (tree == null)
{
Console.WriteLine("未找到您输入的父节点,请重新输入。");
continue;
}

Console.WriteLine("请确定要插入到父节点的:1 左侧,2 右侧");

Direction direction = (Direction)Enum.Parse(typeof(Direction), Console.ReadLine());

tree = mananger.BinTreeAddNode(tree, node, parentData, direction);

Console.WriteLine("插入成功,是否继续?  1 继续, 2 退出");

if (int.Parse(Console.ReadLine()) == 1)
continue;
else
break;
}

return tree;
}
#endregion
}

#region 插入左节点或者右节点
/// <summary>
/// 插入左节点或者右节点
/// </summary>
public enum Direction { Left = 1, Right = 2 }
#endregion

#region 二叉链表存储结构
/// <summary>
/// 二叉链表存储结构
/// </summary>
/// <typeparam name="T"></typeparam>
public class ChainTree<T>
{
public T data;

public ChainTree<T> left;

public ChainTree<T> right;
}
#endregion

/// <summary>
/// 二叉树的操作帮助类
/// </summary>
public class ChainTreeManager
{
#region 按层遍历的Length空间存储
/// <summary>
/// 按层遍历的Length空间存储
/// </summary>
public int Length { get; set; }
#endregion

#region 将指定节点插入到二叉树中
/// <summary>
/// 将指定节点插入到二叉树中
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tree"></param>
/// <param name="node"></param>
/// <param name="direction">插入做左是右</param>
/// <returns></returns>
public ChainTree<T> BinTreeAddNode<T>(ChainTree<T> tree, ChainTree<T> node, T data, Direction direction)
{
if (tree == null)
return null;

if (tree.data.Equals(data))
{
switch (direction)
{
case Direction.Left:
if (tree.left != null)
throw new Exception("树的左节点不为空,不能插入");
else
tree.left = node;

break;
case Direction.Right:
if (tree.right != null)
throw new Exception("树的右节点不为空,不能插入");
else
tree.right = node;

break;
}
}

BinTreeAddNode(tree.left, node, data, direction);
BinTreeAddNode(tree.right, node, data, direction);

return tree;
}
#endregion

#region 获取二叉树指定孩子的状态
/// <summary>
/// 获取二叉树指定孩子的状态
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tree"></param>
/// <param name="direction"></param>
/// <returns></returns>
public ChainTree<T> BinTreeChild<T>(ChainTree<T> tree, Direction direction)
{
ChainTree<T> childNode = null;

if (tree == null)
throw new Exception("二叉树为空");

switch (direction)
{
case Direction.Left:
childNode = tree.left;
break;
case Direction.Right:
childNode = tree.right;
break;
}

return childNode;
}

#endregion

#region 获取二叉树的深度
/// <summary>
/// 获取二叉树的深度
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tree"></param>
/// <returns></returns>
public int BinTreeLen<T>(ChainTree<T> tree)
{
int leftLength;
int rightLength;

if (tree == null)
return 0;

//递归左子树的深度
leftLength = BinTreeLen(tree.left);

//递归右子书的深度
rightLength = BinTreeLen(tree.right);

if (leftLength > rightLength)
return leftLength + 1;
else
return rightLength + 1;
}
#endregion

#region 判断二叉树是否为空
/// <summary>
/// 判断二叉树是否为空
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tree"></param>
/// <returns></returns>
public bool BinTreeisEmpty<T>(ChainTree<T> tree)
{
return tree == null ? true : false;
}
#endregion

#region 在二叉树中查找指定的key
/// <summary>
///在二叉树中查找指定的key
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tree"></param>
/// <param name="data"></param>
/// <returns></returns>
public ChainTree<T> BinTreeFind<T>(ChainTree<T> tree, T data)
{
if (tree == null)
return null;

if (tree.data.Equals(data))
return tree;

return BinTreeFind(tree, data);
}
#endregion

#region 清空二叉树
/// <summary>
/// 清空二叉树
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tree"></param>
public void BinTreeClear<T>(ChainTree<T> tree)
{
//递的结束点,归的起始点
if (tree == null)
return;

BinTreeClear(tree.left);
BinTreeClear(tree.right);

//在归的过程中,释放当前节点的数据空间
tree = null;
}
#endregion

#region 二叉树的先序遍历
/// <summary>
/// 二叉树的先序遍历
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tree"></param>
public void BinTree_DLR<T>(ChainTree<T> tree)
{
if (tree == null)
return;

//先输出根元素
Console.Write(tree.data + "\t");

//然后遍历左子树
BinTree_DLR(tree.left);

//最后遍历右子树
BinTree_DLR(tree.right);
}
#endregion

#region 二叉树的中序遍历
/// <summary>
/// 二叉树的中序遍历
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tree"></param>
public void BinTree_LDR<T>(ChainTree<T> tree)
{
if (tree == null)
return;

//优先遍历左子树
BinTree_LDR(tree.left);

//然后输出节点
Console.Write(tree.data + "\t");

//最后遍历右子树
BinTree_LDR(tree.right);
}
#endregion

#region 二叉树的后序遍历
/// <summary>
/// 二叉树的后序遍历
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tree"></param>
public void BinTree_LRD<T>(ChainTree<T> tree)
{
if (tree == null)
return;

//优先遍历左子树
BinTree_LRD(tree.left);

//然后遍历右子树
BinTree_LRD(tree.right);

//最后输出节点元素
Console.Write(tree.data + "\t");
}
#endregion

#region 二叉树的按层遍历
/// <summary>
/// 二叉树的按层遍历
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tree"></param>
public void BinTree_Level<T>(ChainTree<T> tree)
{
if (tree == null)
return;

//申请保存空间
ChainTree<T>[] treeList = new ChainTree<T>[Length];

int head = 0;
int tail = 0;

//存放数组
treeList[tail] = tree;

//循环链中计算tail位置
tail = (tail + 1) % Length;

while (head != tail)
{
var tempNode = treeList[head];

head = (head + 1) % Length;

//输出节点
Console.Write(tempNode.data + "\t");

//如果左子树不为空,则将左子树存于数组的tail位置
if (tempNode.left != null)
{
treeList[tail] = tempNode.left;

tail = (tail + 1) % Length;
}

//如果右子树不为空,则将右子树存于数组的tail位置
if (tempNode.right != null)
{
treeList[tail] = tempNode.right;

tail = (tail + 1) % Length;
}
}
}
#endregion

}
}


我们把文章开头的“二叉树”的节点输入到我们的结构中,看看遍历效果咋样。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: