二叉树,顺序存储二叉树,线索二叉树

二叉树

介绍

  1. 每个节点最多只能有两个子节点
  2. 子节点分为左子节点和右子节点

遍历

[注]:可以把打印当前节点信息的位置当作一种方法来记忆, 例如先打印当前节点信息然后遍历左右子节点即为前序遍历

结点代码

class Node
{
    public int ID { get; set; }
    public string Name { get; set; }
    public Node Left { get; set; }
    public Node Right { get; set; }

    public Node(int id, string name)
    {
        this.ID = id;
        this.Name = name;
    }

    public override string ToString()
    {
        return $"Node: [ID = {this.ID}, Name = {this.Name}]";
    }
}

前序遍历

static void PreOrder(Node root)
{
    if (root == null)
        return;

    Console.WriteLine(root);
    PreOrder(root.Left);
    PreOrder(root.Right);
}

中序遍历

static void InfixOrder(Node root)
{
    if (root == null)
        return;

    InfixOrder(root.Left);
    Console.WriteLine(root);
    InfixOrder(root.Right);
}

后序遍历

static void PostOrder(Node root)
{
    if (root == null)
        return;

    PostOrder(root.Left);
    PostOrder(root.Right);
    Console.WriteLine(root);
}

查找

查找分为通过前序遍历查找,中序遍历查找,后序遍历查找,思路大致相同
[注]:此代码写在Node的类体中

  1. 判断当前节点是否是带查找节点
  2. 如果是,则返回当前节点
  3. 如果不是,则按前序遍历思路遍历下一节点,继续比对

前序

 public Node PreOrderSearch(int id)
 {
     if (this.ID == id)
         return this;

     Node res = null;
     if (this.Left != null)
         res = this.Left.PreOrderSearch(id);

     //说明在左子树找到
     if (res != null)
         return res;

     if (this.Right != null)
         res = this.Right.PreOrderSearch(id);

     return res;
 }

中序

public Node InfixOrderSearch(int id)
{
    Node res = null;
    if (this.Left != null)
        res = this.Left.InfixOrderSearch(id);
    if (res != null)
        return res;

    if (this.ID == id)
        return this;

    if (this.Right != null)
        res = this.Right.InfixOrderSearch(id);

    return res;
}

后序

public Node PostOrderSearch(int id)
{
    Node res = null;
    if (this.Left != null)
        res = this.Left.PostOrderSearch(id);
    if (res != null)
        return res;

    if (this.Right != null)
        res = this.Right.PostOrderSearch(id);
    if (res != null)
        return res;

    if (this.ID == id)
        return this;

    return null;
}

删除

规定:

  1. 如果删除的节点是叶子节点,则删除该节点
  2. 如果删除的节点是非叶子节点,则删除该子树

思路:

  1. 判断是否为空树,或只有一个root节点
  2. 二叉树是单向的,故实际要找的是待删除节点的父亲节点
  3. 如果当前节点的左子节点是待删除结点,则 this.Left = null
  4. 如果当前节点的右子节点是待删除结点,则 this.Right = null
  5. 如果3,4两步未删除节点,递归左子树 递归右子树

代码

public void Delete(int id)
{
    if (this.Left != null && this.Left.ID == id)
    {
        this.Left = null;
        return;
    }
    if (this.Right != null && this.Right.ID == id)
    {
        this.Right = null;
        return;
    }

    if (this.Left != null)
        this.Left.Delete(id);

    if (this.Right != null)
        this.Right.Delete(id);
}

顺序存储二叉树

介绍

  1. 顺序二叉树通常只考虑完全二叉树
  2. 第n个元素的左子节点为 2n+1
  3. 第n个元素的右子节点为 2n+2
  4. 第n个元素的父亲节点是 (n-1)/2

代码

 class ArrayBinaryTree
 {
     private int[] arr;  //存储节点的数组

     public ArrayBinaryTree(int[] arr)
     {
         this.arr = arr;
     }

     /// <summary>
     /// 
     /// </summary>
     /// <param name="index">数组的下标</param>
     public void PreOrder(int index = 0)
     {
         //如果数组为空或者arr.length == 0
         if (arr == null || arr.Length == 0)
         {
             Console.WriteLine("数组为空");
             return;
         }

         Console.WriteLine(arr[index]);

         //向左递归
         if (index * 2 + 1 < arr.Length)
         {
             PreOrder(2 * index + 1);
         }

         //向右递归
         if (index * 2 + 2 < arr.Length)
         {
             PreOrder(index * 2 + 2);
         }
     }

     public void InfixOrder(int index = 0)
     {
         if (arr == null || arr.Length == 0)
         {
             Console.WriteLine("数组为空");
             return;
         }

         if (2 * index + 1 < arr.Length)
         {
             InfixOrder(2 * index + 1);
         }

         Console.WriteLine(arr[index]);

         if (2 * index + 2 < arr.Length)
         {
             InfixOrder(2 * index + 2);
         }
     }

     public void PostOrder(int index = 0)
     {
         if (arr == null || arr.Length == 0)
         {
             Console.WriteLine("数组为空");
             return;
         }

         if (index * 2 + 1 < arr.Length)
         {
             PostOrder(index * 2 + 1);
         }

         if (index * 2 + 2 < arr.Length)
         {
             PostOrder(index * 2 + 2);
         }

         Console.WriteLine(arr[index]);
     }
 }

线索化二叉树

介绍

  1. n个节点的二叉链表中含有 n+1 个空指针域。利用二叉链表的空指针域,存放指向该节点在某种遍历次序下的前驱和后继节点的指针(这种附加的指针称为“线索”)
    [注]: 二叉树中有n个节点,则有 2n 个指针域。除了根节点外每个节点占一个指针域,故含有 2n-(n-1) = n+1 个空指针域
  2. 这种加上了线索的二叉链表称为线索链表,对应的二叉树称为线索二叉树(Threaded Binarytree) 根据线索性质的不同,线索二叉树可以分为前序线索二叉树,中序线索二叉树和后序线索二叉树三种。

当线索化二叉树后,node节点的属性Left 和Right 有如下情况

  1. Left指向的是左子树,也可能是指向的前驱节点
  2. Right指向的是右子树,也可能是指向后继节点

代码

此时需向Node中添加两个属性 LeftType 和 RightType
//1.如果leftType是0 表示指向的是左子树,如果是1则表示指向前驱节点
//2.如果rightType是0 表示指向的是右子树,如果是1则表示指向后继节点

 class ThreadedBinaryTree
 {
     private Node root;

     //为了实现线索化,需要创建指向当前结点的前驱结点的指针
     private Node pre;
     public Node Root
     {
         set { root = value; }
     }

     public void ThreadNodes()
     {
         this.ThreadNodes(root);
     }

     //遍历线索化二叉树
     public void TraverseThreadedTree()
     {
         Node node = root;
         while (node != null)
         {
             //循环找到leftType == 1 的结点
             while (node.LeftType == 0)
             {
                 node = node.Left;
             }

             //打印当前节点
             Console.WriteLine(node);

             //如果当前结点的右指针指向后继结点,就一直输出
             while (node.RightType == 1)
             {
                 node = node.Right;
                 Console.WriteLine(node);
             }

             //替换遍历的结点
             node = node.Right;
         }
     }

     /// <summary>
     /// 
     /// </summary>
     /// <param name="node">线索化当前结点</param>
     public void ThreadNodes(Node node)
     {
         if (node == null)
             return;

         //(1) 线索化左子树
         ThreadNodes(node.Left);

         //(2) 线索化当前结点
         //处理当前结点的前驱
         if (node.Left == null)
         {
             //让当前结点的左指针指向前驱结点,并修改leftType
             node.Left = pre;
             node.LeftType = 1;
         }

         //处理后继结点
         if (pre != null && pre.Right == null)
         {
             pre.Right = node;
             pre.RightType = 1;
         }
         //后移pre
         pre = node;


         //(3) 线索化右子树
         ThreadNodes(node.Right);
     }

    
 }

补充全部代码

二叉树

using System;

namespace DeleteMethod
{
    class Program
    {
        static void Main(string[] args)
        {
            BinaryTree binaryTree = new BinaryTree();
            Node node1 = new Node(1, "Roy");
            Node node2 = new Node(2, "Summy");
            Node node3 = new Node(3, "Shane");
            Node node4 = new Node(4, "mezz");

            node1.Left = node2;
            node1.Right = node3;
            node3.Right = node4;

            binaryTree.Root = node1;

            Console.WriteLine("删除前");
            binaryTree.PreOrder();

            Console.WriteLine("\n\n");
            Console.WriteLine("删除后");
            binaryTree.Delete(4);
            binaryTree.PreOrder();

        }
    }

    class Node
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public Node Left { get; set; }
        public Node Right { get; set; }

        public Node(int id, string name)
        {
            this.ID = id;
            this.Name = name;
        }

        public void PreOrder()
        {
            Console.WriteLine(this);
            if (this.Left != null)
                this.Left.PreOrder();
            if (this.Right != null)
                this.Right.PreOrder();
        }

        public void InfixOrder()
        {
            if (this.Left != null)
                this.Left.InfixOrder();
            Console.WriteLine(this);
            if (this.Right != null)
                this.Right.InfixOrder();
        }

        public void PostOrder()
        {
            if (this.Left != null)
                this.Left.PostOrder();
            if (this.Right != null)
                this.Right.PostOrder();
            Console.WriteLine(this);
        }

        public Node PreOrderSearch(int id)
        {
            if (this.ID == id)
                return this;

            Node res = null;
            if (this.Left != null)
                res = this.Left.PreOrderSearch(id);

            //说明在左子树找到
            if (res != null)
                return res;

            if (this.Right != null)
                res = this.Right.PreOrderSearch(id);

            return res;
        }

        public Node InfixOrderSearch(int id)
        {
            Node res = null;
            if (this.Left != null)
                res = this.Left.InfixOrderSearch(id);
            if (res != null)
                return res;

            if (this.ID == id)
                return this;

            if (this.Right != null)
                res = this.Right.InfixOrderSearch(id);

            return res;
        }

        public Node PostOrderSearch(int id)
        {
            Node res = null;
            if (this.Left != null)
                res = this.Left.PostOrderSearch(id);
            if (res != null)
                return res;

            if (this.Right != null)
                res = this.Right.PostOrderSearch(id);
            if (res != null)
                return res;

            if (this.ID == id)
                return this;

            return null;
        }

        public void Delete(int id)
        {
            if (this.Left != null && this.Left.ID == id)
            {
                this.Left = null;
                return;
            }
            if (this.Right != null && this.Right.ID == id)
            {
                this.Right = null;
                return;
            }

            if (this.Left != null)
                this.Left.Delete(id);

            if (this.Right != null)
                this.Right.Delete(id);


        }

        public override string ToString()
        {
            return $"Node [ID = {ID}, Name = {Name}].";
        }
    }

    class BinaryTree
    {
        private Node root;

        public Node Root
        {
            set { root = value; }
        }

        public void PreOrder()
        {
            if (this.root != null)
                this.root.PreOrder();
            else
                Console.WriteLine("二叉树为空");
        }

        public void InfixOrder()
        {
            if (this.root != null)
                this.root.InfixOrder();
            else
                Console.WriteLine("二叉树为空");
        }

        public void PostOrder()
        {
            if (this.root != null)
                this.root.PostOrder();
            else
                Console.WriteLine("二叉树为空");
        }

        public Node PreOrderSearch(int id)
        {
            if (root != null)
                return root.PreOrderSearch(id);
            return null;
        }

        public Node InfixOrderSearch(int id)
        {
            if (root != null)
                return root.InfixOrderSearch(id);
            return null;
        }

        public Node PostOrderSearch(int id)
        {
            if (root != null)
                return root.PostOrderSearch(id);
            return null;
        }

        public void Delete(int id)
        {
            if (root != null)
            {
                if (root.ID == id)
                    root = null;
                else
                    root.Delete(id);
            }
            else
                Console.WriteLine("树为空,无法删除");
        }
    }
}

顺序存储二叉树

using System;

namespace ArrBinaryTree
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] arr = { 1, 2, 3, 4, 5, 6, 7 };
            ArrayBinaryTree arrayBinaryTree = new ArrayBinaryTree(arr);
            arrayBinaryTree.PreOrder();
            Console.WriteLine();
            arrayBinaryTree.InfixOrder();
            Console.WriteLine();
            arrayBinaryTree.PostOrder();
        }
    }

    class ArrayBinaryTree
    {
        private int[] arr;  //存储节点的数组

        public ArrayBinaryTree(int[] arr)
        {
            this.arr = arr;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="index">数组的下标</param>
        public void PreOrder(int index = 0)
        {
            //如果数组为空或者arr.length == 0
            if (arr == null || arr.Length == 0)
            {
                Console.WriteLine("数组为空");
                return;
            }

            Console.WriteLine(arr[index]);

            //向左递归
            if (index * 2 + 1 < arr.Length)
            {
                PreOrder(2 * index + 1);
            }

            //向右递归
            if (index * 2 + 2 < arr.Length)
            {
                PreOrder(index * 2 + 2);
            }
        }

        public void InfixOrder(int index = 0)
        {
            if (arr == null || arr.Length == 0)
            {
                Console.WriteLine("数组为空");
                return;
            }

            if (2 * index + 1 < arr.Length)
            {
                InfixOrder(2 * index + 1);
            }

            Console.WriteLine(arr[index]);

            if (2 * index + 2 < arr.Length)
            {
                InfixOrder(2 * index + 2);
            }
        }

        public void PostOrder(int index = 0)
        {
            if (arr == null || arr.Length == 0)
            {
                Console.WriteLine("数组为空");
                return;
            }

            if (index * 2 + 1 < arr.Length)
            {
                PostOrder(index * 2 + 1);
            }

            if (index * 2 + 2 < arr.Length)
            {
                PostOrder(index * 2 + 2);
            }

            Console.WriteLine(arr[index]);
        }
    }
}

线索二叉树

using System;

namespace ThreadedBinaryTreeDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Node root = new Node(1, "Roy");
            Node node2 = new Node(3, "Jack");
            Node node3 = new Node(6, "Smith");
            Node node4 = new Node(8, "Mary");
            Node node5 = new Node(10, "Tim");
            Node node6 = new Node(14, "Summy");

            root.Left = node2;
            root.Right = node3;
            node2.Left = node4;
            node2.Right = node5;
            node3.Left = node6;

            ThreadedBinaryTree tree = new ThreadedBinaryTree();
            tree.Root = root;

            tree.ThreadNodes();

            tree.TraverseThreadedTree();

        }
    }

    class Node
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public Node Left { get; set; }
        public Node Right { get; set; }
        //说明:
        //1.如果leftType是0 表示指向的是左子树,如果是1则表示指向前驱节点
        //2.如果rightType是0 表示指向的是右子树,如果是1则表示指向后继节点
        public int LeftType { get; set; }
        public int RightType { get; set; }

        public Node(int id, string name)
        {
            this.ID = id;
            this.Name = name;
        }

        public void PreOrder()
        {
            Console.WriteLine(this);
            if (this.Left != null)
                this.Left.PreOrder();
            if (this.Right != null)
                this.Right.PreOrder();
        }

        public void InfixOrder()
        {
            if (this.Left != null)
                this.Left.InfixOrder();
            Console.WriteLine(this);
            if (this.Right != null)
                this.Right.InfixOrder();
        }

        public void PostOrder()
        {
            if (this.Left != null)
                this.Left.PostOrder();
            if (this.Right != null)
                this.Right.PostOrder();
            Console.WriteLine(this);
        }

        public Node PreOrderSearch(int id)
        {
            if (this.ID == id)
                return this;

            Node res = null;
            if (this.Left != null)
                res = this.Left.PreOrderSearch(id);

            //说明在左子树找到
            if (res != null)
                return res;

            if (this.Right != null)
                res = this.Right.PreOrderSearch(id);

            return res;
        }

        public Node InfixOrderSearch(int id)
        {
            Node res = null;
            if (this.Left != null)
                res = this.Left.InfixOrderSearch(id);
            if (res != null)
                return res;

            if (this.ID == id)
                return this;

            if (this.Right != null)
                res = this.Right.InfixOrderSearch(id);

            return res;
        }

        public Node PostOrderSearch(int id)
        {
            Node res = null;
            if (this.Left != null)
                res = this.Left.PostOrderSearch(id);
            if (res != null)
                return res;

            if (this.Right != null)
                res = this.Right.PostOrderSearch(id);
            if (res != null)
                return res;

            if (this.ID == id)
                return this;

            return null;
        }

        public void Delete(int id)
        {
            if (this.Left != null && this.Left.ID == id)
            {
                this.Left = null;
                return;
            }
            if (this.Right != null && this.Right.ID == id)
            {
                this.Right = null;
                return;
            }

            if (this.Left != null)
                this.Left.Delete(id);

            if (this.Right != null)
                this.Right.Delete(id);
        }

        public override string ToString()
        {
            return $"Node [ID = {ID}, Name = {Name}].";
        }
    }

    class ThreadedBinaryTree
    {
        private Node root;

        //为了实现线索化,需要创建指向当前结点的前驱结点的指针
        private Node pre;
        public Node Root
        {
            set { root = value; }
        }

        public void ThreadNodes()
        {
            this.ThreadNodes(root);
        }

        //遍历线索化二叉树
        public void TraverseThreadedTree()
        {
            Node node = root;
            while (node != null)
            {
                //循环找到leftType == 1 的结点
                while (node.LeftType == 0)
                {
                    node = node.Left;
                }

                //打印当前节点
                Console.WriteLine(node);

                //如果当前结点的右指针指向后继结点,就一直输出
                while (node.RightType == 1)
                {
                    node = node.Right;
                    Console.WriteLine(node);
                }

                //替换遍历的结点
                node = node.Right;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node">线索化当前结点</param>
        public void ThreadNodes(Node node)
        {
            if (node == null)
                return;

            //(1) 线索化左子树
            ThreadNodes(node.Left);

            //(2) 线索化当前结点
            //处理当前结点的前驱
            if (node.Left == null)
            {
                //让当前结点的左指针指向前驱结点,并修改leftType
                node.Left = pre;
                node.LeftType = 1;
            }

            //处理后继结点
            if (pre != null && pre.Right == null)
            {
                pre.Right = node;
                pre.RightType = 1;
            }
            //后移pre
            pre = node;


            //(3) 线索化右子树
            ThreadNodes(node.Right);
        }

        public void PreOrder()
        {
            if (this.root != null)
                this.root.PreOrder();
            else
                Console.WriteLine("二叉树为空");
        }

        public void InfixOrder()
        {
            if (this.root != null)
                this.root.InfixOrder();
            else
                Console.WriteLine("二叉树为空");
        }

        public void PostOrder()
        {
            if (this.root != null)
                this.root.PostOrder();
            else
                Console.WriteLine("二叉树为空");
        }

        public Node PreOrderSearch(int id)
        {
            if (root != null)
                return root.PreOrderSearch(id);
            return null;
        }

        public Node InfixOrderSearch(int id)
        {
            if (root != null)
                return root.InfixOrderSearch(id);
            return null;
        }

        public Node PostOrderSearch(int id)
        {
            if (root != null)
                return root.PostOrderSearch(id);
            return null;
        }

        public void Delete(int id)
        {
            if (root != null)
            {
                if (root.ID == id)
                    root = null;
                else
                    root.Delete(id);
            }
            else
                Console.WriteLine("树为空,无法删除");
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值