C#使用數組實現二叉查找樹

原創性申明:

本文地址是http://blog.csdn.net/zhujunxxxxx/article/details/40925687 轉載請註明出處。作者聯繫郵箱 [email protected]

二叉排序樹

(Binary Sort Tree)又稱二叉查找樹(Binary Search Tree),亦稱二叉搜索樹。
它或者是一棵空樹;或者是具有下列性質的二叉樹:
(1)若左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 
(2)若右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; 
(3)左、右子樹也分別爲二叉排序樹;



樹的儲方案:

用數組來實現二叉樹,樹上的元素存放位置在數組中是固定的---如果樹的i位置(從1開始按層編號)有元素,就放在數組的i號位置,沒有元素,數組對應的位置就空着。
i的左右子樹的編號爲2i和2i+1。

1,實例變量,容量動態擴展,以及構造方法:

/// <summary>
        /// 數組存儲樹的結構(還有一種是Node)
        /// </summary>
        private int[] data;//從1開始存儲數據
        /// <summary>
        /// 樹的長度
        /// </summary>
        private int len;

        /// <summary>
        /// 刪除節點時用的一個臨時的數據結構
        /// </summary>
        private List<int> tmpList;
        public Tree()
        {   
            //先初始化一個1w大小的數組
            this.data = new int[100];
            tmpList = new List<int>();
            len = 0;
        }

2,樹的插入

數組實現插入其實跟鏈式思想還是一樣,往下找插入節點就是往下找插入的下標,下標的關係已經在前面說過,要注意的是數組容量可能不夠,需要擴展容量
/// <summary>
        /// 把節點插入樹
        /// </summary>
        public void Insert(int key)
        {
            if (len == 0)
            {
                data[1] = key;
                len++;
            }
            else
            {
                int index = 1;
                while (index <data.Length)
                {
                    if (key < data[index])
                    {
                        //拓展數組
                        if (LeftChild(index) >= data.Length)
                            Expand();
                        //判斷這個節點是否爲空
                        if (data[LeftChild(index)] == 0)
                        {
                            data[LeftChild(index)] = key;
                            len++;
                            break;
                        }
                        else
                        {
                            index = LeftChild(index);
                        }
                    }
                    else
                    {
                        //拓展數組
                        if (RightChild(index) >= data.Length)
                            Expand();
                        //判斷這個節點是否爲空
                        if (data[RightChild(index)] == 0)
                        {
                            data[RightChild(index)] = key;
                            len++;
                            break;
                        }
                        else
                        {
                            index = RightChild(index);
                        }
                    }
                }
            }

        }

3,樹的刪除

當某個結點被刪後,它的子樹上的全部結點的下標都要調整,而且這個調整順序還得從上網下調,否則下面的節點的可能覆蓋上面的,
沒有想到什麼好的辦法,最後只有用了一個消耗最大的笨方法---將被刪結點置爲null後,前序遍歷樹(或者後序,不能中序),
將前序序列依次重新插入建樹。相當於刪除節點後,把剩下結點取出來重新建樹
/// <summary>
        /// 刪除樹的節點
        /// </summary>
        public int Delete(int key)
        {
            int value=-1;
            int index = Search(key);
            if (index != -1)
            {
                value=data[index];
                Remove(index);
            }
            return value;
 
        }
        /// <summary>
        /// 移除一個節點,並重新構造樹
        /// </summary>
        /// <param name="index"></param>
        private void Remove(int index)
        {
            //設置要刪除的值爲0
            data[index] = 0;
            //刪除指定下標處的元素,並得到刪除後的樹(調整位置)
            List<int> it = PreInorderList();//得到前序遍歷的迭代器
            for (int i = 1; i < data.Length; i++)//將樹清空
                data[i] = 0;
            //把樹給清空,長度也變爲0
            len = 0;
            foreach (int item in it)
            {
                Insert(item);
            }
        }

4,樹的前序遍歷

 /// <summary>
        /// 先序遍歷
        /// </summary>
        public void PreOrder(int i)
        {
            if (i >= data.Length)
                return;
            if (data[i] != 0)
            {
                tmpList.Add(data[i]);
            }
            PreOrder(LeftChild(i));
            PreOrder(RightChild(i));
 
        }

5,樹的中序遍歷

/// <summary>
        /// 中序遍歷
        /// </summary>
        /// <param name="i"></param>
        public void InOrder(int i)
        {
            if (i >=data.Length)
                return;
            InOrder(LeftChild(i));
            if (data[i] != 0)
            {
                Console.Write(data[i] + " ");
            }
            InOrder(RightChild(i));
        }

6,樹的後續遍歷

/// <summary>
        /// 後續遍歷
        /// </summary>
        /// <param name="i"></param>
        public void PostOrder(int i)
        {
            if (i >= data.Length)
                return;
            PostOrder(LeftChild(i));
            PostOrder(RightChild(i));
            if (data[i] != 0)
            {
                Console.Write(data[i] + " ");
            }
        }

使用實例

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

namespace Other
{
    /// <summary>
    /// 二叉排序樹(Binary Sort Tree)
    /// 二叉查找樹(Binary Search Tree)
    /// </summary>
    public class Tree
    {
        /// <summary>
        /// 數組存儲樹的結構(還有一種是Node)
        /// </summary>
        private int[] data;//從1開始存儲數據
        /// <summary>
        /// 樹的長度
        /// </summary>
        private int len;

        /// <summary>
        /// 刪除節點時用的一個臨時的數據結構
        /// </summary>
        private List<int> tmpList;
        public Tree()
        {   
            //先初始化一個1w大小的數組
            this.data = new int[100];
            tmpList = new List<int>();
            len = 0;
        }
        /// <summary>
        /// 把節點插入樹
        /// </summary>
        public void Insert(int key)
        {
            if (len == 0)
            {
                data[1] = key;
                len++;
            }
            else
            {
                int index = 1;
                while (index <data.Length)
                {
                    if (key < data[index])
                    {
                        //拓展數組
                        if (LeftChild(index) >= data.Length)
                            Expand();
                        //判斷這個節點是否爲空
                        if (data[LeftChild(index)] == 0)
                        {
                            data[LeftChild(index)] = key;
                            len++;
                            break;
                        }
                        else
                        {
                            index = LeftChild(index);
                        }
                    }
                    else
                    {
                        //拓展數組
                        if (RightChild(index) >= data.Length)
                            Expand();
                        //判斷這個節點是否爲空
                        if (data[RightChild(index)] == 0)
                        {
                            data[RightChild(index)] = key;
                            len++;
                            break;
                        }
                        else
                        {
                            index = RightChild(index);
                        }
                    }
                }
            }

        }
        /// <summary>
        /// 刪除樹的節點
        /// </summary>
        public int Delete(int key)
        {
            int value=-1;
            int index = Search(key);
            if (index != -1)
            {
                value=data[index];
                Remove(index);
            }
            return value;
 
        }
        /// <summary>
        /// 移除一個節點,並重新構造樹
        /// </summary>
        /// <param name="index"></param>
        private void Remove(int index)
        {
            //設置要刪除的值爲0
            data[index] = 0;
            //刪除指定下標處的元素,並得到刪除後的樹(調整位置)
            List<int> it = PreInorderList();//得到前序遍歷的迭代器
            for (int i = 1; i < data.Length; i++)//將樹清空
                data[i] = 0;
            //把樹給清空,長度也變爲0
            len = 0;
            foreach (int item in it)
            {
                Insert(item);
            }
        }
        /// <summary>
        /// 獲取先序遍歷的序列
        /// </summary>
        /// <returns></returns>
        private List<int> PreInorderList()
        {
            //生成前序序列
            PreOrder(1);
            List<int> tmp = tmpList;
            //重新把這個初始爲空
            tmpList = new List<int>();
            return tmp;
        }
        /// <summary>
        /// 獲取左孩子
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        private int LeftChild(int i)
        {
            return i * 2;
        }
        /// <summary>
        /// 獲取右孩子
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        private int RightChild(int i)
        {
            return i * 2+1;
        }

        /// <summary>
        /// 當容量不夠的時候拓展數組的大小
        /// </summary>
        private void Expand()
        {
            //一次擴大兩倍
            int[] larger = new int[data.Length * 2];

            for (int i = 1; i < data.Length; i++)
            {
                larger[i] = data[i];
            }
            data = larger;
        }

        /// <summary>
        /// 查找樹節點
        /// </summary>
        public int Search(int key)
        {
            int index = 1;
            while (index < data.Length && data[index] != 0)
            {
                if (data[index] == key)
                    return index;
                else if (key < data[index])
                {
                    index = LeftChild(index);
                }
                else
                {
                    index = RightChild(index);
                }
            }
            return -1;
        }
        /// <summary>
        /// 輸出樹的結構
        /// </summary>
        public override string ToString()
        {
            return null;
        }
        /// <summary>
        /// 先序遍歷
        /// </summary>
        public void PreOrder(int i)
        {
            if (i >= data.Length)
                return;
            if (data[i] != 0)
            {
                tmpList.Add(data[i]);
            }
            PreOrder(LeftChild(i));
            PreOrder(RightChild(i));
 
        }
        /// <summary>
        /// 中序遍歷
        /// </summary>
        /// <param name="i"></param>
        public void InOrder(int i)
        {
            if (i >=data.Length)
                return;
            InOrder(LeftChild(i));
            if (data[i] != 0)
            {
                Console.Write(data[i] + " ");
            }
            InOrder(RightChild(i));
        }
        /// <summary>
        /// 後續遍歷
        /// </summary>
        /// <param name="i"></param>
        public void PostOrder(int i)
        {
            if (i >= data.Length)
                return;
            PostOrder(LeftChild(i));
            PostOrder(RightChild(i));
            if (data[i] != 0)
            {
                Console.Write(data[i] + " ");
            }
        }

    }
}
 static void Main(string[] args)
        {
            Tree t = new Tree();


            
            t.Insert(50);
            t.Insert(20);
            t.Insert(60);
            t.Insert(15);
            t.Insert(30);
            t.Insert(70);


            //從第一個位置開始
            t.InOrder(1);
            Console.WriteLine();
            t.Delete(20);
            t.InOrder(1);
        }



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章