【转】C#实现二叉查找树
原文URL: http://www.cnblogs.com/CareySon/archive/2012/04/19/ImpleBinaryTreeWithCSharp.html
简介
树是一种非线性结构。树的本质是将一些节点由边连接起来,形成层级的结构。而二叉树是一种特殊的树,使得树每个子节点必须小于等于2.而二叉查找树又是一类特殊的二叉树。使得每一个节点的左节点或左子树的所有节点必须小于这个节点,右节点必须大于这个节点。从而方便高效搜索。
下面来看如何使用C#实现二叉查找树。
实现节点
二叉查找树是节点的集合。因此首先要构建节点,如代码1所示。
//二叉查找树的节点定义
public class Node
{
//节点本身的数据
public int data;
//左孩子
public Node left;
//右孩子
public Node right;
public void DisplayData()
{
Console.Write(data+" ");
}
}
代码1.节点的定义
构建二叉树
构建二叉树是通过向二叉树插入元素得以实现的,所有小于根节点的节点插入根节点的左子树,大于根节点的,插入右子树。依此类推进行递归。直到找到位置进行插入。二叉查找树的构建过程其实就是节点的插入过程。C#实现代码如代码2所示。
public void Insert(int data)
{
Node Parent;
//将所需插入的数据包装进节点
Node newNode=new Node();
newNode.data=data; //如果为空树,则插入根节点
if(rootNode==null)
{
rootNode=newNode;
}
//否则找到合适叶子节点位置插入
else
{
Node Current = rootNode;
while(true)
{
Parent=Current;
if(newNode.data<Current.data)
{
Current=Current.left;
if(Current==null)
{
Parent.left=newNode;
//插入叶子后跳出循环
break;
}
}
else
{
Current = Current.right;
if (Current == null)
{
Parent.right = newNode;
//插入叶子后跳出循环
break;
}
}
}
}
}
代码2.实现二叉树的插入
二叉树的遍历
二叉树的遍历分为先序(PreOrder),中序(InOrder)和后序(PostOrder)。先序首先遍历根节点,然后是左子树,然后是右子树。中序首先遍历左子树,然后是根节点,最后是右子树。而后续首先遍历左子树,然后是右子树,最后是根节点。因此,我们可以通过C#递归来实现这三种遍历,如代码3所示。
//中序
public void InOrder(Node theRoot)
{
if (theRoot != null)
{
InOrder(theRoot.left);
theRoot.DisplayData();
InOrder(theRoot.right);
}
}
//先序
public void PreOrder(Node theRoot)
{
if (theRoot != null)
{
theRoot.DisplayData();
PreOrder(theRoot.left);
PreOrder(theRoot.right);
}
}
//后序
public void PostOrder(Node theRoot)
{
if (theRoot != null)
{
PostOrder(theRoot.left);
PostOrder(theRoot.right);
theRoot.DisplayData();
}
}
代码3.实现二叉排序树的先序,中序和后续遍历
找到二叉查找树中的最大值和最小值
二叉查找树因为已经有序,所以查找最大值和最小值非常简单,找最小值只需要找最左边的叶子节点即可。而找最大值也仅需要找最右边的叶子节点,如代码4所示。
//找到最大节点
public void FindMax()
{
Node current = rootNode;
//找到最右边的节点即可
while (current.right != null)
{
current = current.right;
}
Console.WriteLine("\n最大节点为:" + current.data); }
//找到最小节点
public void FindMin()
{
Node current = rootNode;
//找到最左边的节点即可
while (current.left != null)
{
current = current.left;
}
Console.WriteLine("\n最小节点为:" + current.data);
}
代码4.二叉查找树找最小和最大节点
二叉查找树的查找
因为二叉查找树已经有序,所以查找时只需要从根节点开始比较,如果小于根节点,则查左子树,如果大于根节点,则查右子树。如此递归,如代码5所示。
//查找
public Node Search(int i)
{
Node current = rootNode;
while (true)
{
if (i < current.data)
{
if (current.left == null)
break;
current = current.left;
}
else if (i > current.data)
{
if (current == null)
break;
current = current.right;
}
else
{
return current;
}
}
if (current.data != i)
{
return null;
} return current;
}
代码5.二叉查找树的查找
二叉树的删除
二叉树的删除是最麻烦的,需要考虑四种情况:
- 被删节点是叶子节点
- 被删节点有左孩子没右孩子
- 被删节点有右孩子没左孩子
- 被删节点有两个孩子
我们首先需要找到被删除的节点和其父节点,然后根据上述四种情况分别处理。如果遇到被删除元素是根节点时,还需要特殊处理。如代码6所示。
//删除二叉查找树中的节点,最麻烦的操作
public Node Delete(int key)
{
Node parent = rootNode;
Node current = rootNode;
//首先找到需要被删除的节点&其父节点
while (true)
{
if (key < current.data)
{
if (current.left == null)
break;
parent = current;
current = current.left;
}
else if (key > current.data)
{
if (current == null)
break;
parent = current;
current = current.right;
}
//找到被删除节点,跳出循环
else
{
break;
}
}
//找到被删除节点后,分四种情况进行处理
//情况一,所删节点是叶子节点时,直接删除即可
if (current.left == null && current.right == null)
{
//如果被删节点是根节点,且没有左右孩子
if (current == rootNode&&rootNode.left==null&&rootNode.right==null)
{
rootNode = null;
}
else if (current.data < parent.data)
parent.left = null;
else
parent.right = null;
}
//情况二,所删节点只有左孩子节点时
else if(current.left!=null&¤t.right==null)
{
if (current.data < parent.data)
parent.left = current.left;
else
parent.right = current.left; }
//情况三,所删节点只有右孩子节点时
else if (current.left == null && current.right != null)
{
if (current.data < parent.data)
parent.left = current.right;
else
parent.right = current.right; }
//情况四,所删节点有左右两个孩子
else
{
//current是被删的节点,temp是被删左子树最右边的节点
Node temp;
//先判断是父节点的左孩子还是右孩子
if (current.data < parent.data)
{ parent.left = current.left;
temp = current.left;
//寻找被删除节点最深的右孩子
while (temp.right != null)
{
temp = temp.right;
}
temp.right = current.right; }
//右孩子
else if (current.data > parent.data)
{
parent.right = current.left;
temp = current.left;
//寻找被删除节点最深的左孩子
while (temp.left != null)
{
temp = temp.left;
}
temp.right = current.right;
}
//当被删节点是根节点,并且有两个孩子时
else
{
temp = current.left;
while (temp.right != null)
{
temp = temp.right;
}
temp.right = rootNode.right;
rootNode = current.left;
} }
return current; }
代码6.二叉查找树的删除
测试二叉查找树
现在我们已经完成了二叉查找树所需的各个功能,下面我们来对代码进行测试:
BinarySearchTree b = new BinarySearchTree();
/*插入节点*/
b.Insert(5);
b.Insert(7);
b.Insert(1);
b.Insert(12);
b.Insert(32);
b.Insert(15);
b.Insert(22);
b.Insert(2);
b.Insert(6);
b.Insert(24);
b.Insert(17);
b.Insert(14);
/*插入结束 */ /*对二叉查找树分别进行中序,先序,后序遍历*/
Console.Write("\n中序遍历为:");
b.InOrder(b.rootNode);
Console.Write("\n先序遍历为:");
b.PreOrder(b.rootNode);
Console.Write("\n后序遍历为:");
b.PostOrder(b.rootNode);
Console.WriteLine(" ");
/*遍历结束*/ /*查最大值和最小值*/
b.FindMax();
b.FindMin();
/*查找结束*/ /*搜索节点*/
Node x = b.Search(15);
Console.WriteLine("\n所查找的节点为" + x.data);
/*搜索结束*/ /*测试删除*/
b.Delete(24);
Console.Write("\n删除节点后先序遍历的结果是:");
b.InOrder(b.rootNode);
b.Delete(5);
Console.Write("\n删除根节点后先序遍历的结果是:");
b.InOrder(b.rootNode);
Console.ReadKey();
/*删除结束*/
代码7.测试二叉查找树
运行结果如图1所示:

图1.测试运行结果
总结
树是节点的层级集合,而二叉树又是将每个节点的孩子限制为小于等于2的特殊树,二叉查找树又是一种特殊的二叉树。二叉树对于查找来说是非常高效,尤其是查找最大值和最小值。
【转】C#实现二叉查找树的更多相关文章
- 数据结构:二叉查找树(C语言实现)
数据结构:二叉查找树(C语言实现) ►写在前面 关于二叉树的基础知识,请看我的一篇博客:二叉树的链式存储 说明: 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: 1.若其左子树不空,则左子树上 ...
- 数据结构笔记--二叉查找树概述以及java代码实现
一些概念: 二叉查找树的重要性质:对于树中的每一个节点X,它的左子树任一节点的值均小于X,右子树上任意节点的值均大于X. 二叉查找树是java的TreeSet和TreeMap类实现的基础. 由于树的递 ...
- codevs 1285 二叉查找树STL基本用法
C++STL库的set就是一个二叉查找树,并且支持结构体. 在写结构体式的二叉查找树时,需要在结构体里面定义操作符 < ,因为需要比较. set经常会用到迭代器,这里说明一下迭代器:可以类似的把 ...
- 平衡二叉查找树(AVL)的理解与实现
AVL树的介绍 平衡二叉树,又称AVL(Adelson-Velskii和Landis)树,是带有平衡条件的二叉查找树.这个平衡条件必须要容易保持,而且它必须保证树的深度是 O(log N).一棵AVL ...
- 二叉查找树 C++实现(含完整代码)
一般二叉树的查找是通过遍历整棵二叉树实现,效率较低.二叉查找树是一种特殊的二叉树,可以提高查找的效率.二叉查找树又称为二叉排序树或二叉搜索树. 二叉查找树的定义 二叉排序树(Binary Search ...
- 数据结构——二叉查找树、AVL树
二叉查找树:由于二叉查找树建树的过程即为插入的过程,所以其中序遍历一定为升序排列! 插入:直接插入,插入后一定为根节点 查找:直接查找 删除:叶子节点直接删除,有一个孩子的节点删除后将孩子节点接入到父 ...
- Java for LintCode 验证二叉查找树
给定一个二叉树,判断它是否是合法的二叉查找树(BST) 一棵BST定义为: 节点的左子树中的值要严格小于该节点的值. 节点的右子树中的值要严格大于该节点的值. 左右子树也必须是二叉查找树. ...
- 数据结构和算法 – 9.二叉树和二叉查找树
9.1.树的定义 9.2.二叉树 人们把每个节点最多拥有不超过两个子节点的树定义为二叉树.由于限制子节点的数量为 2,人们可以为插入数据.删除数据.以及在二叉树中查找数据编写有效的程序了. 在 ...
- 二叉树-二叉查找树-AVL树-遍历
一.二叉树 定义:每个节点都不能有多于两个的儿子的树. 二叉树节点声明: struct treeNode { elementType element; treeNode * left; treeNod ...
- 二叉查找树的Java实现
为了克服对树结构编程的恐惧感,决心自己实现一遍二叉查找树,以便掌握关于树结构编程的一些技巧和方法.以下是基本思路: [1] 关于容器与封装.封装,是一种非常重要的系统设计思想:无论是面向过程的函数,还 ...
随机推荐
- cocos2d-x 手电筒效果
转自:http://blog.csdn.net/xujiezhige/article/details/8448524# 常见的手电筒效果,可以通过CCRenderTexture来实现.主要是通过修改渲 ...
- TcxDBLookupCombobox 级联时第二级不显示正确内容的处理方法
在使用两个级联的 TcxDBLookupCombobox 时,会出现这种情况:当第一级的内容变更后,第二级的控件在界面上显示的文本不变化,即使数据集已经通过 Properites.OnChange 事 ...
- 瑞丽的SQL-基于窗体的排名计算
在SQL Server中,窗体被定义为用户指定的一组行. 之所以要提出窗体这个概念,由于这种基于窗体或分区的又一次计算在实际工作应用范围比較广泛.比如.假设我们要对每一个班级中的学生按成绩进行排序,在 ...
- 创建MySQL从库
我们知道Oracle有DataGuard实时备份数据.能够做主备切换,而MySQL也有自己的一套备库方案.称之为主从复制. 搭建MySQL从库是为了实时同步主库数据,同一时候也能够分担主库的读压力.对 ...
- day05 Java基础
1.数组初始化:为数组开辟内存空间,并为每个数组元素赋予值.数组初始化方式: 方式一:动态初始化:初始化时只指定数组长度,由系统为数组分配初始值. 格式:数组类型[] 数组名称=new 数组类型[数组 ...
- 探索 Linux 内存模型--转
引用:http://www.ibm.com/developerworks/cn/linux/l-memmod/index.html 理解 Linux 使用的内存模型是从更大程度上掌握 Linux 设计 ...
- Maven 仓库
Maven仓库分为本地仓库和远程仓库(中央仓库,私服,其他公共仓库)一张图就可以很清楚的看出结构 本地仓库:本地仓库是在我们当前电脑系统盘的user-administrator-m2-reposito ...
- 学习SDAutoLayout第三方库的用法总结
---恢复内容开始--- 在做图文混排计算高度我觉得SDAutoLayout布局是最好用的第三方库了,这里学习SDAutoLayout用法总结一下 用法介绍: ) 方法名中带有“SpaceToView ...
- CSS skills: 3) show sub-navigate items when mouse hove on nav-item
<header> <div class="am-g am-g-fixed"> <ul class="am-avg-lg-2 topbar f ...
- MSSQL系统表常用操作
1:获取当前数据库中的所有用户表 select Name from sysobjects where xtype='u' and status>=0 2:获取某一个表的所有字段 select n ...