算法系列15天速成——第十一天 树操作(上)
2011-12-11 00:18
477 查看
最近项目赶的紧,歇了一个星期没写博客了,趁周末继续写这个系列。
先前我们讲的都是“线性结构”,他的特征就是“一个节点最多有一个”前驱“和一个”后继“。那么我们今天讲的树会是怎样的呢?
我们可以对”线性结构“改造一下,变为”一个节点最多有一个"前驱“和”多个后继“。哈哈,这就是我们今天说的”树“。
一: 树
我们思维中的”树“就是一种枝繁叶茂的形象,那么数据结构中的”树“该是怎么样呢?对的,他是一种现实中倒立的树。
View Code
我们把文章开头的“二叉树”的节点输入到我们的结构中,看看遍历效果咋样。
先前我们讲的都是“线性结构”,他的特征就是“一个节点最多有一个”前驱“和一个”后继“。那么我们今天讲的树会是怎样的呢?
我们可以对”线性结构“改造一下,变为”一个节点最多有一个"前驱“和”多个后继“。哈哈,这就是我们今天说的”树“。
一: 树
我们思维中的”树“就是一种枝繁叶茂的形象,那么数据结构中的”树“该是怎么样呢?对的,他是一种现实中倒立的树。
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 } }
我们把文章开头的“二叉树”的节点输入到我们的结构中,看看遍历效果咋样。
相关文章推荐
- 算法系列15天速成——第十一天 树操作(上)
- 算法系列15天速成——第十一天 树操作(上)
- 算法系列15天速成——第十一天 树操作(上)
- 算法系列15天速成 第十一天 树操作(上)
- 算法系列15天速成——第十一天 树操作(上)
- 算法系列15天速成——第十一天 树操作(上)
- 算法系列15天速成——第十一天 树操作(上)
- 算法系列15天速成——第十二天 树操作【中】
- 算法系列15天速成——第十三天 树操作【下】
- 算法系列15天速成——第十三天 树操作【下】
- 算法系列15天速成——第十二天 树操作【中】
- 算法系列15天速成 第十二天 树操作【中】
- 算法系列15天速成——第十二天 树操作(中)
- 算法系列15天速成—— 第十三 树操作【下】
- 算法系列15天速成——第十三天 树操作【下】
- 算法系列15天速成——第十二天 树操作【中】
- 算法系列15天速成——第十三天 树操作【下】
- 算法系列15天速成——第十二天 树操作【中】
- 算法系列15天速成——第十二天 树操作【中】
- 算法系列15天速成——第十三天 树操作【下】