知识大全 二叉排序树的C#实现
Posted 结点
篇首语:三人行必有我师焉;择其善者而从之,其不善者而改之。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 二叉排序树的C#实现相关的知识,希望对你有一定的参考价值。
二叉排序树的C#实现 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
二叉排序树说起来其实并不是很难 二叉查找树是一种把值比较小的节点存储在左子节点内而值比较大的节点存储在右子节点里的树 其基本操作有以下几种
插入
我们对这个二叉树插入节点 如果二叉树本身没有任何节点 那么插入的这个节点就成为根节点 否则 根据定义 你应该遍历树 找出某一个节点 如果带插入节点的值大于这个节点 则成为带插入节点的右节点 否则就是左节点 从这里看来 根节点本身就是一个树的节点 因此 我首先实现了一个TreeNode类型 如下
: public class TreeNode<T>:IComparable IComparable<TreeNode<T>>
:
: #region ctor 串联构造函数
:
: public TreeNode():this(default(T) null null )
:
:
: public TreeNode(T value):this(value null null )
:
:
: public TreeNode(T value TreeNode<T> leftNode TreeNode<T> rightNode):this(value leftNode rightNode )
:
:
: public TreeNode(T value TreeNode<T> leftNode TreeNode<T> rightNode int deepness)
: Value = value;
: LeftNode = leftNode;
: RightNode = rightNode;
: Deepness = deepness;
: IsLeaf = true;
:
:
: public override string ToString()
: return Value ToString();
:
:
: #endregion
:
: #region Interface Members
:
: int IComparable CompareTo(Object item)
: TreeNode<T> node = item as TreeNode<T>;
: if (node == null)
: throw new ArgumentException( Argument for paring is not a object of TreeNode Type !! );
: else
: if (this == item)
: return ;
: else
: Comparer parer = new Comparer(CultureInfo CurrentCulture);
: return parer Compare(this Value node Value);
:
:
:
:
: int IComparable<TreeNode<T>> CompareTo(TreeNode<T> item)
: if (item == null)
: throw new ArgumentException( Argument for paring is not a object of TreeNode Type !! );
: else
: if (this == item)
: return ;
: else
: Comparer parer = new Comparer(CultureInfo CurrentCulture);
: return parer Compare(this Value item Value);
:
:
:
: #endregion
:
: #region Properties
:
: public TreeNode<T> LeftNode
: get;
: set;
:
:
: public TreeNode<T> RightNode
: get;
: set;
:
:
: public TreeNode<T> FatherNode
: get;
: set;
:
:
: //这个属性是指数的层数 也就是深度 根的深度为
: public int Deepness
: get;
: set;
:
:
: //这个属性指示这个节点是不是叶子节点
: public bool IsLeaf
: get;
: set;
:
:
: //这个属性返回或者设置该节点的值
: public T Value
: get;
: set;
:
:
: #endregion
:
接下来我们就能实现插入的功能了 通常我觉得好的代码是自描述的 也就是一段好的代码应该能自己描述自己的用途的
: public void Add(T itemValue)
: if (Root == null)
: TreeNode<T> root = new TreeNode<T>(itemValue);
: this Root = root;
: this Count++;
: else
: TreeNode<T> _iterator = this Root;
: bool okFlag = true;;
: int deepness = ;
: int result = _parer Compare(itemValue _iterator Value); ;
:
: while (okFlag)
: Debug WriteLine( Comaper Result is : + result ToString());
: Debug WriteLine( );
: if (result > )
: if (_iterator RightNode != null)
: _iterator = _iterator RightNode;
: result = _parer Compare(itemValue _iterator Value);
: deepness++;
: else
: //在添加节点的时候就设置该节点的深度 而在计算整棵树的深度的时候 其实只要对所有叶节点的深度的值进行排序就可以得到了
: _iterator RightNode = new TreeNode<T>(itemValue null null deepness);
: _iterator IsLeaf = false;
: _iterator RightNode FatherNode = _iterator;
: Count++;
: okFlag = false;
:
: else if (result < )
: if (_iterator LeftNode != null)
: _iterator = _iterator LeftNode;
: result = _parer Compare(itemValue _iterator Value);
: deepness++;
: else
: _iterator LeftNode = new TreeNode<T>(itemValue null null deepness);
: _iterator IsLeaf = false;
: _iterator LeftNode FatherNode = _iterator;
: Count++;
: okFlag = false;
:
: else
: okFlag = false;
:
:
:
这里在比较的时候 我是在全局设置了一个与本地文化相关的Comparer类型的私有成员_parer 这个类型用于对象判等 关键是你要判断的对象必须实现IComparable 接口 我编写的TreeNode类型就实现了这个接口了
查找
根据二叉搜索树的特点 如果你要搜索的节点的值比当前节点值小 那么就再搜索该节点的左子树 否则 搜索右子树 这个过程是递归过程
如果找到匹配的节点 返回ture;否则 当前节点为Null 然后又不等于你要搜索的节点的值 那么就直接返回false 我的实现如下
: public bool IsExit(T key out TreeNode<T> node)
: node = null;
: TreeNode<T> _iterator = Root;
: int result = _parer Compare(key _iterator Value);
: bool okFlag = true;
: while (okFlag)
: if (result == )
: okFlag = false;
: node = _iterator;//如果找到这个叶子结点 那么得到叶子节点的指针
: return true;
: else if (result > )
: _iterator = _iterator RightNode;
: if (_iterator != null)
: result = _parer Compare(key _iterator Value);
: else
: okFlag = false;
: return false;
:
: else
: _iterator = _iterator LeftNode;
: if (_iterator != null)
: result = _parer Compare(key _iterator Value);
: else
: okFlag = false;
: return false;
:
:
:
: return false;
:
遍历
这个分三种情况的遍历 分别是前根遍历 中根遍历 后根遍历 其实很简单 就是按照访问节点的顺序来划分的 如果先访问左子节点 然后访问父节点 最后在访问右节点 这个情况就是前序遍历 其他的情况以此类推 这里我实现的时候 是用递归的方式
: /// <summary>
: /// 中根遍历树
: /// </summary>
: /// <param name= root ></param>
: public void InOrder(TreeNode<T> root)
: if (root != null)
: InOrder(root LeftNode);
: Console WriteLine(string Format( This node s value is and it s deepness is leaf: root ToString() root Deepness ToString() root IsLeaf ToString()));
: InOrder(root RightNode);
:
:
:
: /// <summary>
: /// 先根遍历树
: /// </summary>
: /// <param name= root ></param>
: public void PreOrder(TreeNode<T> root)
: if (root != null)
: Console WriteLine(string Format( This node s value is and it s deepness is leaf: root ToString() root Deepness ToString() root IsLeaf ToString()));
: PreOrder(root LeftNode);
: PreOrder(root RightNode);
:
:
:
: /// <summary>
: /// 后根遍历树
: /// </summary>
: /// <param name= root ></param>
: public void PostOrder(TreeNode<T> root)
: if (root != null)
: PostOrder(root LeftNode);
: PostOrder(root RightNode);
: string Format( This node s value is and it s deepness is leaf: root ToString() root Deepness ToString() root IsLeaf ToString());
:
:
删除节点
作为这个树的实现里面最有难度的地方 要考虑三种情况
要删除的节点时叶子结点 这个情况很好解决 直接删掉就好了
要删除的节点只有一个子节点 这个情况也很好解决 子节点替换一下父节点 问题解决
要删除的节点有两个节点 这个就比较复杂了一些 但我们仔细分析 就会发现 要删除这个节点 只要利用中根遍历得到直接前驱或者直接后继结点代替该节点就可以了 同时 你还要删除前驱或者后继这个节点 而这两个节点 一定符合前面的两种情况之一
: public void Remove(T key)
: TreeNode<T> node;
: bool isExit = IsExit(key out node);
: if (!isExit)
: return;
: else
: if (IsLeafNode(node))
: if (node FatherNode LeftNode == node)
: node FatherNode LeftNode = null;
: else
: node FatherNode RightNode = null;
: if (node != null) node = null;
: else
: if (!HasTwoLeafNodes(node))
: TreeNode<T> child = GetUniqueChild(node);
: if (node FatherNode LeftNode == node)
: node FatherNode LeftNode = child;
: else
: if (node LeftNode != null)
: node FatherNode RightNode = child;
:
: if (node != null) node = null;
: else
: //首先找到后继结点
: TreeNode<T> successor = GetSuccessor(node);
: //调整节点值 这个时候有一个值得注意的地方 比如你的树是这样的情况
: /* 或者
: * \\ /
: *
: * / \\ / \\
: * / \\
: * / \\ /
: * / \\ / \\
: *
: * \\
: *
: */
: //树A中节点 相应的后继结点应该是 那么 的左子节点应调整成 就要调整成
: node Value = successor Value;
: Remove(successor);
:
:
: this Count ;
:
:
以下是完整的代码 尽管是泛型 但其实我仅仅使用int类型编写 过测试 如果其他的类型 我想只要是实现了IComparable接口 应该就能正常工作
: using System;
: using System Collections;
: using System Collections Generic;
: using System Globalization;
: using System Diagnostics;
: using System Text;
:
: namespace Ultis
: public class BinaryTree<T>
: #region ctor
:
: static BinaryTree()
: _parer = new Comparer(CultureInfo CurrentCulture);
:
:
: public BinaryTree()
: this Root = null;
: this Count = ;
: this _deepness = ;
:
:
: public BinaryTree(TreeNode<T> root)
: if (root == null)
: throw new ArgumentException( Root can not be null !! );
:
: this Root = root;
: this Count++;
: this _deepness = ;
:
: #endregion
:
: #region Public Members
:
: /// <summary>
: ///
: /// </summary>
: /// <param name= itemValue ></param>
: public void Add(T itemValue)
: if (Root == null)
: TreeNode<T> root = new TreeNode<T>(itemValue);
: this Root = root;
: this Count++;
: else
: TreeNode<T> _iterator = this Root;
: bool okFlag = true;;
: int deepness = ;
: int result = _parer Compare(itemValue _iterator Value); ;
:
: while (okFlag)
: Debug WriteLine( Comaper Result is : + result ToString());
: Debug WriteLine( );
: if (result > )
: if (_iterator RightNode != null)
: _iterator = _iterator RightNode;
: result = _parer Compare(itemValue _iterator Value);
: deepness++;
: else
: //在添加节点的时候就设置该节点的深度 而在计算整棵树的深度的时候 其实只要对所有叶节点的深度的值进行排序就可以得到了
: _iterator RightNode = new TreeNode<T>(itemValue null null deepness);
: _iterator IsLeaf = false;
: _iterator RightNode FatherNode = _iterator;
: Count++;
: okFlag = false;
:
: else if (result < )
: if (_iterator LeftNode != null)
: _iterator = _iterator LeftNode;
: result = _parer Compare(itemValue _iterator Value);
: deepness++;
: else
: _iterator LeftNode = new TreeNode<T>(itemValue null null deepness);
: _iterator IsLeaf = false;
: _iterator LeftNode FatherNode = _iterator;
: Count++;
: okFlag = false;
:
: else
: okFlag = false;
:
:
:
:
: /// <summary>
: /// 从树中移出一个节点 要考虑很多情况 比如要删除的节点没有子节点 有一个子节点 有两个子节点
: /// PS:这个方法应进行测试
: /// </summary>
: /**
: * 删除指定的节点实现
: *
: * 算法思想
: *
: * 若待删除的节点p是叶子节点 则直接删除该节点
: *
: * 若待删除的节点p只有一个子节点 则将p的子节点与p的父节点直接连接 然后删除节点p
: * 为什么只有一个子节点时可以直接接到删除节点的父节点下面呢?因为只有一个子节点 直接接上
: * 去不会影响排序子节点本身的排序 当然更不会影响另外一个子树(因为另一子树跟本不存在!)
: *
: * 若待删除节点p有两个子节点时 应该使用中序遍历方式得到的直接前置节点S或直接后继节点s
: * 的值来代替点s的值 然后删除节点s (注 节点s肯定属于上述 情况之一)而不是直接删除
: * p 这样可以将该删除问题转换成上面 问题
: */
: public void Remove(T key)
: TreeNode<T> node;
: bool isExit = IsExit(key out node);
: if (!isExit)
: return;
: else
: if (IsLeafNode(node))
: if (node FatherNode LeftNode == node)
: node FatherNode LeftNode = null;
: else
: node FatherNode RightNode = null;
: if (node != null) node = null;
: else
: if (!HasTwoLeafNodes(node))
: TreeNode<T> child = GetUniqueChild(node);
: if (node FatherNode LeftNode == node)
: node FatherNode LeftNode = child;
: else
: if (node LeftNode != null)
: node FatherNode RightNode = child;
:
: if (node != null) node = null;
: else
: //首先找到后继结点
: TreeNode<T> successor = GetSuccessor(node);
: //调整节点值 这个时候有一个值得注意的地方 比如你的树是这样的情况
: /* 或者
: * \\ /
: *
: * / \\ / \\
: * / \\
: * / \\ /
: * / \\ / \\
: *
: * \\
: *
: */
: //树A中节点 相应的后继结点应该是 那么 的左子节点应调整成 就要调整成
: node Value = successor Value;
: Remove(successor);
:
:
: this Count ;
:
:
:
:
: /**
: * 删除指定的节点实现
: *
: * 算法思想
: *
: * 若待删除的节点p是叶子节点 则直接删除该节点
: *
: * 若待删除的节点p只有一个子节点 则将p的子节点与p的父节点直接连接 然后删除节点p
: * 为什么只有一个子节点时可以直接接到删除节点的父节点下面呢?因为只有一个子节点 直接接上
: * 去不会影响排序子节点本身的排序 当然更不会影响另外一个子树(因为另一子树跟本不存在!)
: *
: * 若待删除节点p有两个子节点时 应该使用中序遍历方式得到的直接前置节点S或直接后继节点s
: * 的值来代替点s的值 然后删除节点s (注 节点s肯定属于上述 情况之一)而不是直接删除
: * p 这样可以将该删除问题转换成上面 问题
: */
: public void Remove(TreeNode<T> node)
: if (IsLeafNode(node))
: if (node FatherNode LeftNode == node)
: node FatherNode LeftNode = null;
: else
: node FatherNode RightNode = null;
: if (node != null) node = null;
: else
: if (!HasTwoLeafNodes(node))
: TreeNode<T> child = GetUniqueChild(node);
: if (node FatherNode LeftNode == node)
: node FatherNode LeftNode = child;
: else
: node FatherNode RightNode = child;
:
: if(node != null) node = null;
: else
: //要删除的节点有两个子节点
: TreeNode<T> successor = GetSuccessor(node);
: node Value = successor Value;
: Remove(successor); //删除相应的后继结点
: if (successor != null) successor = null;
:
:
: this Count ;
:
:
: /// <summary>
: /// 返回某一节点唯一的一个节点
: /// </summary>
: /// <param name= node ></param>
: /// <returns></returns>
: private TreeNode<T> GetUniqueChild(TreeNode<T> node)
: TreeNode<T> child;
: if (node LeftNode != null)
: child = node LeftNode;
: else
: child = node RightNode;
: return child;
:
:
: /// <summary>
: /// 根据中根遍历来得到相应的后继结点 仍然还有BUG存在!
: /// </summary>
: /// <param name= value ></param>
: /// <returns></returns>
: public TreeNode<T> GetSuccessor(T value)
: throw new NotImplementedException( This function is not plete yet ! );
: IComparable iparable = Root as IComparable;
: TreeNode<T> wanted = new TreeNode<T>(value);
: if (iparable CompareTo(wanted) == )
: return Root;
: else
: TreeNode<T> node;
: if (IsExit(value out node))
: if (IsLeafNode(node)) //如果是叶子节点 那么应该做么做才能返回正确的后继节点?
: return null;
: else
: return GetSuccessor(node); //如果是非叶子节点 则调用相应的方法返回非叶子节点的后继结点
: else
: return null;
:
:
:
: /// <summary>
: /// 中根遍历树
: /// </summary>
: /// <param name= root ></param>
: public void InOrder(TreeNode<T> root)
: if (root != null)
: InOrder(root LeftNode);
: Console WriteLine(string Format( This node s value is and it s deepness is leaf: root ToString() root Deepness ToString() root IsLeaf ToString()));
: InOrder(root RightNode);
:
:
相关参考
()二叉排序树的删除 从二叉排序树中删除一个结点不能把以该结点为根的子树都删去并且还要保证删除后所得的二叉树仍然满足BST性质 ①删除操作的一般步骤 ()进行查找 查找时令p指向当前访问到
)在二叉排序树上进行查找时的平均查找长度和二叉树的形态有关 二分查找法查找长度为n的有序表其判定树是惟一的含有n个结点的二叉排序树却不惟一对于含有同样一组结点的表由于 结点插入的先后次序不同所
二叉树遍历算法C#实现 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 用C#实现了二叉树的定义怎
(四)树与二叉树的应用 二叉排序树 定义 二叉排序树(也称二叉查找树)或者是一棵空的二叉树或者是具有下列性质的二叉树 ()若它的左子树不空则左子
知识大全 数据结构考研分类复习真题 第六章 树和二叉树 (三)[6]
.一个无序序列可以通过构造一棵______树而变成一个有序序列构造树的过程即为对无序序列进行排序的过程【西安电子科技大学软件一(分)】 .利用树的孩子兄弟表示法存储可以将一棵树转换为______
二叉树是树形结构的一个重要类型许多实际问题抽象出来的数据结构往往是二叉树的形式即使是一般的树也能简单地转换为二叉树而且二叉树的存储结构及其算法都较为简单因此二叉树显得特别重要二叉树的定义二叉树的递
二叉树是树形结构的一个重要类型许多实际问题抽象出来的数据结构往往是二叉树的形式即使是一般的树也能简单地转换为二 叉树而且二叉树的存储结构及其算法都较为简单因此二叉树显得特别重要 二叉树的定义
二叉树的特殊形态 满二叉树(FullBinaryTree)一棵深度为k且有k个结点的二叉树 特点二叉树的所有分支结点都存在左子树和右子树 特点二叉树的所有叶子结点都在同一层上 完全二叉树(Co
链式存储结构 结点的结构 二叉树的每个结点最多有两个孩子用链接方式存储二叉树时每个结点除了存储结点本身的数据外还应设置两个指针域 lchild和rchild分别指向该结点的左孩子和右孩子结点
顺序存储结构 该方法是把二叉树的所有结点按照一定的线性次序存储到一片连续的存储单元中结点在这个序列中的相互位置还能反映出结点 之间的逻辑关系 完全二叉树结点编号 ()编号办法 在一棵n个