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 中序遍历
先遍历输出左结点,再输出当前结点的数据,再遍历输出右结点GDHB 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(); } } }