数据结构与算法C#语言描述第12章二叉树

第十二章二叉树和二叉查找树

12.1 树的定义

12.2 二叉树

12.2.1 构造二叉查找树

using System;
using System.Collections.Generic;

using System.Text;

/*******************************

* 创建二叉树,并显示出来 *
 ***********************/
namespace BinaryTree
{
    class Program
    {
        static void Main(string[] args)
        {
            BinarySearchTree nums = new BinarySearchTree();
            nums.Insert(23);
            nums.Insert(45);
            nums.Insert(16);
            nums.Insert(37);
            nums.Insert(3);
            nums.Insert(99);
            nums.Insert(22);
            //nums.Insert(23);
            //nums.Insert(23);
            //nums.Insert(23);
            //nums.Insert(23);

            Console.WriteLine("Inorder traversasl:");
            nums.InOrder(nums.root);
            Console.ReadKey();

        }
    }

    public class Node
    {
        public int Data;

        public Node Left=null;
        public Node Right=null;

        public void DisplayNode()
        {
            Console.Write(Data+" ");
        }
    }

    public class BinarySearchTree
    {
        public Node root;
        public BinarySearchTree()
        {
            root = null;
        }
        public void InOrder(Node theRoot)
        {
            if(!(theRoot==null))
            {
                InOrder(theRoot.Left);
                theRoot.DisplayNode();
                InOrder(theRoot.Right);
            }
        }

        public void Insert(int i )
        {
            Node newNode = new Node();
            newNode.Data = i;

            if (root == null)
            {
                root = newNode;
            }
            else
            {
                Node current = root;
                Node parent;
                while(true)
                {
                    parent = current;
                    if (i < current.Data)
                    {
                        current = current.Left;
                        if (current == null)
                        {
                           
                            parent.Left = newNode;
                            break;
                        }
                    }
                    else
                    {
                        current = current.Right;
                        if (current == null)
                        {
                            parent.Right = newNode;
                            break;
                        }
                    }
                }
            }
        }
    }
}

12.2.2 遍历二叉查找树

using System;
public class Node {
   public int Data;
   public Node Left;
   public Node Right;
   public void DisplayNode() {
   Console.Write(Data + " ");
       }
   }   
public class BinarySearchTree
{
       public Node root;
       public BinarySearchTree()
          {
             root = null;
          }
 
       public void Insert(int i)
          {
           Node newNode = new Node();
           newNode.Data = i;
           if (root == null)
              root = newNode;
           else
             {
              Node current = root;
              Node parent;
              while (true) {
                  parent = current;
                  if (i < current.Data) {
                     current = current.Left;
                     if (current == null) {
                        parent.Left = newNode;
                        break;
                     }
              else {
                    current = current.Right;
                    if (current == null) {
                       parent.Right = newNode;
                       break;
                }}}}}}
    public void InOrder(Node theRoot) {
   if (!(theRoot == null)) {
      InOrder(theRoot.Left);
      theRoot.DisplayNode();
      InOrder(theRoot.Right);
   }
            }
}
class Program{
 public static void Main() {
       Console.Write("test");
   BinarySearchTree nums = new BinarySearchTree();
   nums.Insert(23);
   nums.Insert(45);
   nums.Insert(16);
   nums.Insert(37);
   nums.Insert(3);
   nums.Insert(99);
   nums.Insert(22);
   Console.WriteLine("Inorder traversal: ");
   nums.InOrder(nums.root);
    }
}

12.2.3 在二叉查找树种查找节点和最大/最小值

12.2.4 从二叉查找树中移除叶子结点

至少与本节要讨论的移除操作相比,到目前为止在二叉查找树(以下简称BST)上执行的操作都不复杂。对于某些情况而言,从BST中移除节点几乎是微不足道的。但是对另外一些情况而言,它却需要对其代码有特别的关注,否则会有破坏BST正确层次顺序的风险。研究从BST中移除节点就先从讨论一个最简单的实例开始吧,这个实例就是移除叶子。因为不需要考虑子节点的问题,所以移除叶子是最简单的事情。唯一要做的就是把目标节点的父节点的每一个子节点设置为空(null)。当然,节点始终存在,只是与该节点没有任何连接了。

移除叶子节点的代码段如下所示(此代码也包括了Delete方法的开始部分,这部分内容声明了一些数据成员,并且移动到了要删除的节点上):

public bool Delete(int key)
{
Node current = root;
Node parent = root;
bool isLeftChild = true;
while (current.Data != key)
{
parent = current;
if (key < current.Data)
{
isLeftChild = true;
current = current.Right;
}
else
{
isLeftChild = false;
current = current.Right;
}
if (current == null)
return false;
}
if ((current.Left == null) & (current.Right == null))
if (current == root)
root = null;
else if (isLeftChild)
parent.Left = null;
else
parent.Right = null;
return true;
//the rest of the class goes here
}

while循环会取走要删除的节点。第一个检测是查看这个节点的左子节点和右子节点是否为空(null)。然后检测这个节点是否是根节点。如果是,就把它设置为空(null)。否则,既把父节点的左子节点设置为空(null)(如果isLeftChild为真),也把父节点的右子节点设置为空(null)。

12.2.5删除带有一个子节点的节点

当要删除的节点有一个子节点的时候,需要检查4个条件:1.这个节点的子节点可能是左子节点;2.这个节点的子节点可能是右子节点;3.要删除的这个节点可能是左子节点;4.要删除的这个节点可能是右子节点。

else if (current.Right == null)
if (current == root)
root = current.Left;
else if (isLeftChild)
parent.Left = current.Left;
else
parent.Right = current.Right;
else if (current.Left == null)
if (current == root)
root = current.Right;
else if (isLeftChild)
parent.Left = parent.Right;
else
parent.Right = current.Right;

首先,查看右子节点是否为空(null)。如果是,就接着查看是否在根节点上。如果在,就把左子节点移动到根节点上。否则,如果当前节点是左子节点,那么把新的父节点的左子节点设置为当前的左子节点。或者,如果在右子节点上,那么把父节点的右子节点设置为当前的右子节点。

12.2.6 删除带有两个子节点的节点

这个问题的答案是把中序后继节点移动到要删除节点的位置上。这个工作很容易做,除非后继节点本身有子节点。但是即使它有子节点,仍然还是有办法解决的。图12-7展示了如何利用中序后继节来实现这个操作。

为了找到后继节点,要到原始节点的右子节点上。根据定义这个节点必须比原始节点大。然后,开始沿着左子节点路径走直到节点用完为止。既然子树(像一棵树)内的最小值必须是在左子节点路径的末端,沿着这条路径到达末端就会找到大于原始节点的最小节点。

下面是找到要删除节点的后继节点的代码:

public Node GetSuccessor(Node delNode)
{
Node successorParent = delNode;
Node successor = delNode;
Node current = delNode.Right;
while (!(current == null))
{
successorParent = current;
successor = current;
current = current.Left;
}
if (!(successor == delNode.Right))
{
successorParent.Left = successor.Right;
successor.Right = delNode.Right;
}
return successor;
}

现在需要看两种特殊情况:后继节点是要删除节点的右子节点,以及后继节点是要删除节点的左子节点。先从第一种情况开始。

首先把要删除的节点标记为当前节点。接着把此节点从其父节点的右子节点中移除,并且把父节点的右子节点指向后继节点。然后,移除当前节点的左子节点,并且把后继节点的左子节点设置为当前节点的左子节点。此操作的代码如下所示:

else
{
Node successor = GetSuccessor(current);
if (current == root)
root = successor;
else if (isLeftChild)
parent.Left = successor;
else
parent.Right = successor;
successor.Left = current.Left;
}

现在一起来看看当后继节点是要删除节点的左子节点的情况。执行此操作的算法描述如下:

(1) 把后继节点的右子节点赋值为后继节点的父节点的左子节点;

(2) 把要删除节点的右子节点赋值为后继节点的右子节点;

(3) 从父节点的右子节点中移除当前节点,并且把它指向后继节点;

(4) 从当前节点中移除当前节点的左子节点,并且把它指向后继节点的左子节点。

这个算法的部分内容是在GetSuccessor方法中实现的,还有部分内容是在Delete方法中实现的。GetSuccessor方法的代码段如下所示:

if (!(successor == delNode.Right))
{
successorParent.Left = successor.Right;
successor.Right = delNode.Right;
}

Delete方法的代码如下所示:

if (current == root)
root = successor;
else if (isLeftChild)
parent. Left = successor;
else
parent.Right = successor;
successor.Left = current.Left;

这是Delete方法的完整代码。因为这个方法有些复杂,所以一些二叉查找树的实现简单地标记要删除的节点,并且在执行查找和遍历的时候包含了检查标记的代码。

下面是Delete方法的完整代码:

public bool Delete(int key)
{
Node current = root;
Node parent = root;
bool isLeftChild = true;
while (current.Data != key)
{
parent = current;
if (key < current.Data)
{
isLeftChild = true;
current = current.Right;
}
else
{
isLeftChild = false;
current = current.Right;
}
if (current == null)
return false;
}
if ((current.Left == null) & (current.Right == null))
if (current == root)
root = null;
else if (isLeftChild)
parent.Left = null;
else if (current.Right == null)
if (current == root)
root = current.Left;
else if (isLeftChild)
parent.Left = current.Left;
else
parent.Right = current.Right;
else if (current.Left == null)
if (current == root)
root = current.Right;
else if (isLeftChild)
parent.Left = parent.Right;
else
parent.Right = current.Right;
else
{
Node successor = GetSuccessor(current);
if (current == root)
root = successor;
else if (isLeftChild)
parent.Left = successor;
else
parent.Right = successor;
successor.Left = current.Left;
}
return true;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值