【转】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&&current.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的特殊树,二叉查找树又是一种特殊的二叉树。二叉树对于查找来说是非常高效,尤其是查找最大值和最小值。

时间: 2024-10-11 06:24:46

【转】C#实现二叉查找树的相关文章

C语言实现二叉查找树

#include<stdio.h> #include<stdlib.h> /* * 数据结构:二叉查找树,即左孩子<父节点<右孩子 * C语言实现 * 2015-9-13 */ typedef struct TreeNode *PtrToNode; typedef PtrToNode Tree; typedef PtrToNode Position; struct TreeNode { int Element; Tree Left; //节点左孩子 Tree Right

按层遍历二叉查找树

<算法>中二叉查找树一节的习题:按层遍历二叉查找树. 可以使用队列来管理二叉查找树中的节点,节点按照如下方法入队出队: 节点x入队 当队列不为空时使用队列的第一个元素first 如果节点first.left不为空则将fisrt.left入队 如果节点first.right不为空则将first.right入队 将first节点出队 /** * Created by elvalad on 2014/12/5. * 按层遍历二叉查找树 */ import java.util.Iterator; im

二叉查找树BST 模板

二叉查找树BST 就是二叉搜索树 二叉排序树. 就是满足 左儿子<父节点<右儿子 的一颗树,插入和查询复杂度最好情况都是logN的,写起来很简单. 根据BST的性质可以很好的解决这些东西 1.查询值 int Search(int k,int x) { if(x<a[k].key && a[k].l) Search(a[k].l,x); else if(x>a[k].key && a[k].r) Search(a[k].r,x); else retur

二叉查找树

二叉查找(搜索)树(Binary Search Tree)又称二叉排序树(Binary Sort Tree),是基于二叉树,BST具有下列性质:1.若左子树不空,则其左子树上的所有结点的值均小于根结点的值:2.若右子树不空,则其右子树上的所有结点的值均大于根结点的值:3.左.右子树也分别为二叉查找树. 结点类 public class BinaryNode {      Integer data;      BinaryNode leftChild;      BinaryNode rightC

平衡树初阶——AVL平衡二叉查找树+三大平衡树(Treap + Splay + SBT)模板【超详解】

平衡树初阶——AVL平衡二叉查找树 一.什么是二叉树 1. 什么是树. 计算机科学里面的树本质是一个树状图.树首先是一个有向无环图,由根节点指向子结点.但是不严格的说,我们也研究无向树.所谓无向树就是将有向树的所有边看成无向边形成的树状图.树是一种递归的数据结构,所以我们研究树也是按照递归的方式去研究的. 2.什么是二叉树. 我们给出二叉树的递归定义如下: (1)空树是一个二叉树. (2)单个节点是一个二叉树. (3)如果一棵树中,以它的左右子节点为根形成的子树都是二叉树,那么这棵树本身也是二叉

java 二叉查找树

//接口+抽象类+实现类package wangChaoPA实习工作练习.com.进阶篇.二叉查找树; import java.util.Iterator;public interface Tree<E extends Comparable<E>>{    // 从树中删除e    boolean delete(E e); // 树的大小    int getSize(); // 中序遍历树    void inorder(); // 把e插入到tree中    boolean i

二叉查找树C++实现

二分查找树特点: (1) 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值: (2) 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值: (3) 任意节点的左.右子树也分别为二叉查找树. (4) 没有键值相等的节点(no duplicate nodes). 前序遍历:中左右 中序遍历:左中右 序遍历:左右中 二叉查找树的重点在于如何找节点的前驱节点和后继节点 #pragma once #include <iostream> using namespace st

[二叉查找树] 二叉排序树

题目描述 输入一系列整数,建立二叉排序数,并进行前序,中序,后序遍历. 输入 输入第一行包括一个整数n(1<=n<=100).接下来的一行包括n个整数. 输出 可能有多组测试数据,对于每组数据,将题目所给数据建立一个二叉排序树,并对二叉排序树进行前序.中序和后序遍历.每种遍历结果输出一行.每行最后一个数据之后有一个空格. 样例输入 1 2 2 8 15 4 21 10 5 39 样例输出 2 2 2 8 15 8 15 15 8 21 10 5 39 5 10 21 39 5 10 39 21

图解数据结构(7)——二叉查找树及平衡二叉查找树(一共14篇)

这篇将是最有难度和挑战性的一篇,做好心理准备!十.二叉查找树(BST)前一篇介绍了树,却未介绍树有什么用.但就算我不说,你也能想得到,看我们Windows的目录结构,其实就是树形的,一个典型的分类应用.当然除了分类,树还有别的作用,我们可以利用树建立一个非常便于查找取值又非常便于插入删除的数据结构,这就是马上要提到的二叉查找树(Binary Search Tree),这种二叉树有个特点:对任意节点而言,左子(当然了,存在的话)的值总是小于本身,而右子(存在的话)的值总是大于本身. 这种特性使得我

二叉查找树 _ 二叉排序树 _ 二叉搜索树_C++

一.数据结构背景+代码变量介绍 二叉查找树,又名二叉排序树,亦名二叉搜索树 它满足以下定义: 1.任意节点的子树又是一颗二叉查找树,且左子树的每个节点均小于该节点,右子树的每个节点均大于该节点. 2.由1可推出,任意节点的左孩子小于该节点,右孩子大于该节点 以上讨论的是左(右)孩子(子树)存在的情况 它的中序遍历是一个升序的排序 在参考代码中,我们定义有: 主程序中,k代表插入或删除或查找的节点的值 root,根节点位置:a[i],第 i 号节点的值:cl[i],第 i 号节点左孩子的位置:cr