树_二叉树

1. 树

1.1 什么是树


1.2 树的存储结构

存储结构一般是顺序存储和链式存储。

树的关系复杂使用链式存储

(1)双亲表示法


(2)孩子表示法


(3)孩子兄弟表示法


2. 二叉树



2.1 特殊的二叉树

(1)斜树
 左斜树
  右斜树

(2)满二叉树


(3)完全二叉树


2.2 二叉树性质

(1)在二叉树的第 i 层上最多有 2 i-1 个结点( i >=1
(2)深度为 k 的二叉树至多有 2 k -1 个结点
  2 0 +2 1 +2 2 +2 3 +2 4 +2 5 +2 6 +2 7 +.....+2 k-1 +-1
  =1+2 0 +2 1 +2 2 +2 3 +2 4 +2 5 +2 6 +2 7 +.....+2 k-1 -1
  = 2 1 +2 1 +2 2 +2 3 +2 4 +2 5 +2 6 +2 7 +.....+2 k-1 -1
  = 2 2 +2 2 +2 3 +2 4 +2 5 +2 6 +2 7 +.....+2 k-1 -1
  =2 3 +2 3 +2 4 +2 5 +2 6 +2 7 +.....+2 k-1 -1
  =2 k-1 +2 k-1 -1
  =2 k -1
(3) 对于一个完全二叉树,假设它有 n 个结点,对结点进行从 1 开始编号,对任一结点 i 满足下面
  a ,它的双亲是结点 i /2  ( 除了 i =1 的情况 )
  b ,左孩子是 2i  右孩子是 2i+1

c,如果2i>n说明无左孩子   2i+1>n说明无右孩子

2.3 二叉树存储结构

        一般的树来说是一对多的关系,使用顺序结构存储起来比较困难,但是二叉树是一种特殊的树,每个结点最多有两个子节点,并且子节点有左右之分,并且兄弟,父亲,孩子可以很方便的通过编号得到,所以我们使用顺序存储结构使用二叉树的存储。

2.3.1 存储结构1



2.3.2 存储结构2



2.3.3 存储结构3


        顺序存储一般只用于完全二叉树

2.4 二叉树-二叉链表存储

        二叉树每个结点最多有两个孩子,所以为它设计一个数据域和两个指针域,我们称这样的链表为二叉链表。


2.5 二叉树的遍历

        二叉树的遍历是指从根结点出发,按照某种次序依次访问二叉树中的所有结点,使得每个结点被访问一次且仅被访问一次。

2.5.1 前序遍历

          先输出当前结点的数据,再依次遍历输出左结点和右结点
  A   (B)     (C)
                B (D)     C (E) F
                  D G H     E I

           A B D G H C E I

2.5.2 中序遍历

          先遍历输出左结点,再输出当前结点的数据,再遍历输出右结点

    GHB A E I C F

2.5.3 后序遍历

    先遍历输出左结点,再遍历输出右结点,最后输出当前结点的数据

 G H D B I E F C A

2.5.4 层序遍历

        从树的第一层开始,从上到下逐层遍历,在同一层中,从左到右对结点逐个访问输出

3. 二叉排序树

二叉排序树,又称为二叉查找树。它或者是一棵空树,或者是具有下列性质的二叉树。
   若它的左子树不为空,则左子树上所有的结点的值均小于根结构的值;
   若它的右子树不为空,则右字数上所有结点的值均大于它的根结点的值;

它的左右子树也分别为二叉排序树。

1 ,排序方便
2 ,方便查找

3,方便插入和删除

3.1 二叉排序树-删除



二叉排序树删除
(1)叶子结点
(2)仅有左子树或者右子数的结点

(3)左右子树都有

3.2 二叉排序树-存储

          因为二叉排序树的存储,跟自身值的大小有关系,并不是想之前学习的完全二叉树使用顺序结构可以存储的,所以我们使用链式结构存储二叉排序树。

3.3 代码实现二叉排序树

        代码实现二叉排序树的存储,插入,删除,查找。

3.3.1 BSNode.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _504_二叉排序树_链式储存
{
    class BSNode
    {
        public BSNode LeftChild { get; set; }
        public BSNode RightChild { get; set; }
        public BSNode Parent { get; set; }

        public int Data { get;  set; }

        public BSNode()
        { }
        public BSNode(int item)
        {
            this.Data = item;
        }
    }
}

3.3.2 BSTree.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _504_二叉排序树_链式储存
{
    class BSTree
    {
        BSNode root = null;

        public void Add(int item)
        {
            BSNode newNode = new BSNode(item);

            if(root==null)
            {
                root = newNode;
            }
            else
            {
                BSNode temp = root;
                while(true)
                {
                    if(temp.Data<=item)//放在temp右边
                    {
                        if (temp.RightChild == null)
                        {
                            temp.RightChild = newNode;
                            newNode.Parent = temp;
                            break;
                        }
                        else
                        {
                            temp = temp.RightChild;
                        }
                    }
                    else//放在temp左边
                    {
                        if(temp.LeftChild==null)
                        {
                            temp.LeftChild = newNode;
                            newNode.Parent = temp;
                            break;
                        }
                        else
                        {
                            temp = temp.LeftChild;
                        }
                    }
                }
            }
        }

        public void MidelTraversal()
        {
            MidelTraversal(root);
        }
        private void MidelTraversal(BSNode temp)
        {
            if(temp==null)
            {
                return;
            }
            else
            {
                MidelTraversal(temp.LeftChild);
                Console.Write(temp.Data + " ");
                MidelTraversal(temp.RightChild);
            }
        }

        public bool Find(int item)
        {
            //return Find(item, root);
            return Find2(item, root);
        }
        /// <summary>
        /// 全部遍历查找
        /// </summary>
        /// <param name="item"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        private bool Find(int item,BSNode node)
        {
            if(node==null)
            {
                return false;
            }
            if(item==node.Data)
            {
                return true;
            }
            else
            {
                if(Find(item,node.RightChild))
                {
                    return true;
                }
                if(Find(item,node.LeftChild))
                {
                    return true;
                }

            }
            return false;
        }
        /// <summary>
        /// 改进的查找,非全部遍历,当查找值大于结点值,就遍历右子树,否则遍历左子树
        /// </summary>
        /// <param name="item"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        private bool Find2(int item,BSNode node)
        {
            if(node==null)
            {
                return false;
            }
            if(item==node.Data)
            {
                return true;
            }
            else
            {
                if(item>node.Data)
                {
                    return  Find2(item, node.RightChild);
                }
                else
                {
                    return Find2(item, node.LeftChild);
                }
            }
        }
        /// <summary>
        /// 非递归遍历查找,利用循环查找
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool Find3(int item)
        {
            BSNode node = root;
            
            while (true)
            {
                if (node == null) return false;
                if (node.Data == item) return true;
                else
                {
                    if (node.Data < item)
                    {
                        node = node.RightChild;
                    }
                    else
                    {
                        node = node.LeftChild;
                    }
                }
            }
        }
        public bool Delete(int item)
        {
            BSNode node = root;

            while (true)
            {
                if (node == null) return false;
                if (node.Data == item)
                {
                    Delete(node);
                    return true;
                }
                else
                {
                    if (node.Data < item)
                    {
                        node = node.RightChild;
                    }
                    else
                    {
                        node = node.LeftChild;
                    }
                }
            }
        }
        public void Delete(BSNode node)
        {
            
            //1.要删除的结点的左右子树都为空
            if (node.RightChild == null && node.LeftChild == null)
            {
                if (node.Parent == null)//要删除的是根节点
                {
                    root = null;
                }
                else if (node.Parent.LeftChild == node)//要删除的结点是父节点的左孩子
                {
                    node.Parent.LeftChild = null;
                }
                else if (node.Parent.RightChild == node)//要删除的结点是父节点的右孩子
                {
                    node.Parent.RightChild = null;
                }
                return;
            }
            //2.要删除的结点的右孩子为空,左孩子不为空
            if (node.RightChild == null && node.LeftChild != null)
            {
                node.Data = node.LeftChild.Data;
                node.LeftChild = null;
            }
            //3.要删除的结点的右孩子不为空,左孩子为空
            if (node.RightChild != null && node.LeftChild == null)
            {
                node.Data = node.RightChild.Data;
                node.RightChild = null;
            }

            //4.要删除的结点的左右孩子都不为空(就从当前结点的左右子树中找到一个左右孩子的中间值,有两种方法,一种从左子树中找一个最大值,一方法是从右子树中找一个最小值
            BSNode currentNode = node.RightChild;
            while(true)
            {
                if(currentNode.LeftChild!=null)
                {
                    currentNode = currentNode.LeftChild;
                }
                else
                {
                    break;
                }
            }
            //循环结束后,currentNode保存的就是叶子节点
            node.Data = currentNode.Data;
            Delete(currentNode);
        }
    }
}

3.3.3 Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _504_二叉排序树_链式储存
{
    class Program
    {
        static void Main(string[] args)
        {
            BSTree bSTree = new BSTree();
            int[] data = { 62, 58, 88, 47, 73, 99, 35, 51, 93, 37 };
            foreach(int t in data)
            {
                bSTree.Add(t);
            }
            bSTree.MidelTraversal();
            Console.WriteLine();
            Console.WriteLine(bSTree.Find(99));
            Console.WriteLine(bSTree.Find(100));
            Console.WriteLine(bSTree.Find3(62));
            bSTree.Delete(62);
            bSTree.MidelTraversal();
            Console.ReadKey();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/a962035/article/details/79930169