数据结构-二叉树、搜索树、平衡二叉树详解及C语言实现

目录

1、 树概念及结构

1.1、树的概念

树是一种数据结构,它是由n(n≥1)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
每个节点有零个或多个子节点;没有父节点的节点称为根节点;每一个非根节点有且只有一个父节点;除了根节点外,每个子节点可以分为多个不相交的子树。

1.2、树的定义

树(Tree) :n (n>=0) 个结点构成的有限集合。
当n=0时,称为空树;
对于任一棵非空树(n>0),它具备以下性质:
树中有一个称为“根(Root)”的特殊结点,用r表示;
其余结点可分为m(m>0)个互不相交的有限集T1, T2,…,Tm,其
中每个集合本身又是一棵树,称为原来树的“子树(SubTree)”
在这里插入图片描述

1.3、树的一些基本术语

1.结点的度(Degree) :结点的子树个数
2.树的度:树的所有结点中最大的度数
3.叶结点(Leaf) :度为0的结点
4.父结点(Parent) :有子树的结点是其子树的根结点的父结点
5.子结点(Child) :若A结点是B结点的父结点,则称B结点是A结点的子结点;子结点也称孩子结点。
6.兄弟结点(Sibling) :具有同一父结点的各结点彼此是兄弟结点。
7. 路径和路径长度:从结点n1到n的路径为个结点序列n1, N2… ,∩k, n,是n+1的父结点。路径所包含边的个数为路径的长度。
9.祖先结点(Ancestor):沿树根到某- -结点路径_上的所有结点都是这个结点的祖先结点。
10.子孙结点(Descendant):某一结 点的子树中的所有结点是这个结点的子孙。
11.结点的层次(Level) :规定根结点在1层,其它任一结点的层数是其父结点的层数加1。
12.树的深度(Depth) :树中所有结点中的最大层次是这棵树的深度。

1.4、树的表示
1.4.1、儿子兄弟表示法

树结构中,位于同一层的节点之间互为兄弟节点。
孩子兄弟表示法,采用的是链式存储结构,其存储树的实现思想是:从树的根节点开始,依次用链表存储各个节点的孩子节点和兄弟节点。即一个节点第一个指针指向第一个儿子,第二个指针指向另一个兄弟。

数据结构表示为:
节点的值;
指向孩子节点的指针;
指向兄弟节点的指针;
typedef struct CSNode{
    ElemType data;
    struct CSNode * firstchild,*nextsibling;
}

在这里插入图片描述

1.4.2、双亲表示法

双亲表示法采用顺序表存储普通树,其实现的核心思想是:顺序存储各个节点的同时,给各节点附加一个记录其父节点位置的变量。

1.4.3、孩子表示法

孩子表示法存储普通树采用的是 “顺序表+链表” 的组合结构,其存储过程是:从树的根节点开始,使用顺序表依次存储树中各个节点,需要注意的是,与双亲表示法不同,孩子表示法会给各个节点配备一个链表,用于存储各节点的孩子节点位于顺序表中的位置。

2、二叉树及存储结构

2.1、二叉树的定义

二叉树T:一个有穷的结点集合。
这个集合可以为空
若不为空,则它是由根结点和称为其左子树TL右子树Tp
两个不相交的二叉树组成。
二叉树具体五种基本形态,二叉树的子树有左右顺序之分。

在这里插入图片描述

2.2、特殊的二叉树
2.2.1、斜二叉树

在这里插入图片描述

2.2.2、完美二叉树(满二叉树)

在这里插入图片描述

2.2.3、完全二叉树

有n个结点的二叉树,对树中结点按从上至下、从左到右顺序进行编号,
编号为i (1≤i≤n)结点与满二叉树中编号为i结点在二叉树中位置相同

在这里插入图片描述

2.3、二叉树的性质

一个二叉树第i层的最大结点数为: 2-1,i≥1。
深度为k的二叉树有最大结点总数为:2 k_1, k≥1。
对任何非空二叉树T,若n。表示叶结点的个数、n,是度为2的非叶结点个数,那么两者满足关系n。=n, +1。

2.4、顺序结构(缺点造成空间浪费)

完全二叉树:按从_上至下、从左到右顺序存储n个结 点的完全二叉树的结点父子关系:

在这里插入图片描述
非根结点(序号i> 1)的父结点的序号是li/2];
结点(序号为i )的左孩子结点的序号是2i,(若2i<=n,否则没有左孩子) ;
结点(序号为i)的右孩子结点的序号是2i+1,(若2i+1<=n, 否则没有右孩子)
|节点  |  A|B||--|--||序号  | ||||||

2.5、链式结构实现(有代码)
2.5.1、结构体定义
typedef int  ElementType; 
typedef struct TNode{ /* 树结点定义 */
   ElementType Data; /* 结点数据 */
   struct TNode *Left;     /* 指向左子树 */
   struct TNode *Right;    /* 指向右子树 */
}BiTNode,*BinTree;
2.5.2、创建二叉树
BinTree CreateBinTree(BinTree *T)    //BinTree是个指针类型,指向一个结构体  所以传入的参数是一个结构体指针的指针 
{
    int ch;
    scanf("%d",&ch);
    if (ch == -1)    //当ch输入为-1时,代表指针域为NULL 
    {
        *T = NULL;    //将指针域设为空,这里*T为 TNode类型指针 
        return;         //不返回任何值 
    }
    else
    {
        *T = (BinTree)malloc(sizeof(BiTNode));    
        (*T)->Data = ch;
        printf("请输入%d的左子节点:",ch);
        CreateBinTree(&((*T)->Left));   //利用递归创建二叉树   
        printf("请输入%d的右子节点:",ch);
        CreateBinTree((&(*T)->Right));   //(*T)->Right是个TNode类型指针 ,&为取地址符。&(*T)->Right)取指针的地址 
    }

    return;
}
2.5.3、销毁二叉树

void DestroyBiTree(BinTree *T)   //销毁一个二叉树 
{
if(*T)
{
if((*T)->Left) // 有左孩子 
DestroyBiTree(&(*T)->Left); //销毁左孩子子树 
if((*T)->Right) // 有右孩子 
DestroyBiTree(&(*T)->Right); // 销毁右孩子子树 
free(*T); // 释放根结点 
*T=NULL; // 空指针赋0 
}

}
2.5.3、先序遍历二叉树

先序遍历:
遍历过程:
1.先访问根节点
2.先序遍历其左子树
3.先序遍历其右子树

在这里插入图片描述
先序遍历结果为:ABDFECGHI
先序递归实现:

void PreOrderTraversalBiTree(BinTree T)   //先序遍历二叉树
{
    if (T == NULL)
    {
        return;
    }
    else
    {
        printf("%d ",T->Data);
        PreOrderTraversalBiTree(T->Left);
        PreOrderTraversalBiTree(T->Right);
    }
}

先序非递归实现:
遇到一个节点,就把它压栈,并访问这个节点,并去遍历它的左子树;
当左子树遍历结束后;
然后按其有指针再去前序遍历该节点的右子树。

int PreOrderTraver(BinTree T){   //先序遍历非递归法 
    BinTree temp = T;
   Stack s = CreatStack(MAX_SIZE); 
    while(temp != NULL || s.top != 0 ){

        while(temp != NULL)// 先遍历左子树;
        {
           
            Push(s,temp);
                 printf("%d ", temp -> Data);
            temp = temp ->Left;
        }
        if (s.top != 0){
            temp = Pop(s);
      
            temp = temp ->Right;
        }

    }
       return 0;

}
2.5.3、中序遍历二叉树

先序遍历:
遍历过程:
1.中序遍历其左子树
2.先访问根节点
3.中序遍历其右子树

在这里插入图片描述
中序遍历结果为:DBEFAGHCI
中序遍历递归实现:

void MiddleOrderTraversalBiTree(BinTree T)  //中序遍历二叉树
{
    if (T == NULL)
    {
        return;
    }
    else
    {
    
        MiddleOrderTraversalBiTree(T->Left);
          printf("%d ",T->Data);
        MiddleOrderTraversalBiTree(T->Right);
    }
}

中序遍历非递归实现:

遇到一个节点,就把它压栈,并去遍历它的左子树;
当左子树遍历结束后,从栈顶弹出这个节点并访问它;
然后按其有指针再去前序遍历该节点的右子树。

int MiddleOrder(BinTree T){   //中序遍历非递归法 
    BinTree temp = T;
    Stack s = CreatStack(MAX_SIZE); 
    while(temp != NULL || s.top != 0 ){

        while(temp != NULL)// 先遍历左子树;
        {
           
            Push(s,temp);
            temp = temp ->Left;
        }
        if (s.top != 0){
            temp = Pop(s);
            printf("%d ", temp -> Data);
            temp = temp ->Right;
        }

    }
       return 0;

}
  
2.5.4、后序遍历二叉树

后序遍历:
遍历过程:
1.后序遍历其左子树
2.后序遍历其右子树
3.再访问根节点

在这里插入图片描述
遍历结果:DEFBHGICA
后序遍历递归实现:

void PostOrderTraversaBiTree(BinTree T)   //后续遍历二叉树
{
    if (T == NULL)
    {
        return;
    }
    else
    {
       PostOrderTraversaBiTree(T->Left);
        
    PostOrderTraversaBiTree(T->Right);
          printf("%d ",T->Data);
    }
}

后序遍历非递归代码
实现思路:先创建两个堆。
1.S1作为调整堆,开始先从根节点先右子树开始把节点压入栈,当最后一个节点的右子树为空时,将该节点出栈,并访问该节点的左子树;
2.当左子树为空时:继续出栈
3.当左子树不为空时:将该节点入栈
4.s2记录着入栈的顺序,将这里节点依次出栈即完成后序遍历。
在这里插入图片描述
s1:ACI入栈 I出C出 G入 H入 H出,G出,B入 F入 F出 E入 E出 B出 D入
s2 ACI入栈 G入栈 H入 B入 F入 E入 D入
在把s2出栈得到顺序为:DEFBHGICA

void PostOrderTraversal(BinTree BT)
{
    BinTree T = BT;
    Stack s1 = CreatStack(MAX_SIZE);    //创建并初始化堆栈S1
    Stack s2 = CreatStack(MAX_SIZE);    //创建并初始化堆栈S2   
    while(T || !IsEmpty(S1))
    {
        while(T)        //一直向右并将沿途节点访问(压入S2)后压入堆栈S1 
        {
            Push(s2, T);
            Push(s1, T);
            
            T = T->Right;
        }
        if (!IsEmpty(S1))
        {
            T = Pop(s1) ;    //节点弹出堆栈
            T = T->Left;  //转向左子树
        }
    }
    while(!IsEmpty(s2))    //访问(打印)S2中元素
    {
        T = Pop(s2);
        printf("%d\n", T->Data);
    }          
}

在这里插入图片描述

2.6、层次遍历

队列实现:遍历从根节点开始,首先根节点入队,然后开始执行循环:节点出队、访问该节点、其左右儿子入队。

层次遍历基本过程:先根节点入队,然后:
1.从队列中取出一个元素;
2.访问该节点指向的节点;
3.若该元素所指的左、右孩子节点非空,则将其左、右孩子的指针顺序入队。

void LevelorderTraversal ( BinTree BT )
{ 
    Queue Q; 
    BinTree T;

    if ( !BT ) return; /* 若是空树则直接返回 */
    
    Q = CreatQueue(); /* 创建空队列Q */
    AddQ( Q, BT );
    while ( !IsEmpty(Q) ) {
        T = DeleteQ( Q );
        printf("%d ", T->Data); /* 访问取出队列的结点 */
        if ( T->Left )   AddQ( Q, T->Left );
        if ( T->Right )  AddQ( Q, T->Right );
    }
}
2.7、二叉树的深度
int TreeDeep( BinTree T)  //二叉树的深度
{
    int deep = 0;
    if (T != NULL)
    {
        int leftdeep = TreeDeep(T->Left);
        int rightdeep = TreeDeep(T->Right);
        deep = leftdeep >= rightdeep?leftdeep+1:rightdeep+1;
    }

    return deep;
}
2.8、叶子节点个数
int LeafCount(BinTree T)  //叶子节点个数
{
    static int count;
    if (T != NULL)
    {
        if (T->Left == NULL && T->Right == NULL)
        {
             count++;
        }

        LeafCount(T->Left);
        LeafCount(T->Right);
    }

    return count;
}
2.8、完整的代码
#include <stdio.h>
#include <stdlib.h>



typedef int  ElementType; 
typedef struct TNode{ /* 树结点定义 */
    ElementType Data; /* 结点数据 */
   struct TNode *Left;     /* 指向左子树 */
    struct TNode *Right;    /* 指向右子树 */
}BiTNode,*BinTree;


//先序创建二叉树
BinTree CreateBinTree(BinTree *T)    //BinTree是个指针类型,指向一个结构体  所以传入的参数是一个结构体指针的指针 
{
    int ch;
    scanf("%d",&ch);
    if (ch == -1)    //当ch输入为-1时,代表指针域为NULL 
    {
        *T = NULL;    //将指针域设为空,这里*T为 TNode类型指针 
        return;         //不返回任何值 
    }
    else
    {
        *T = (BinTree)malloc(sizeof(BiTNode));    
        (*T)->Data = ch;
        printf("请输入%d的左子节点:",ch);
        CreateBinTree(&((*T)->Left));   //利用递归创建二叉树   
        printf("请输入%d的右子节点:",ch);
        CreateBinTree((&(*T)->Right));   //(*T)->Right是个TNode类型指针 ,&为取地址符。&(*T)->Right)取指针的地址 
    }

    return;
}







void DestroyBiTree(BinTree *T)   //销毁一个二叉树 
{
if(*T)
{
if((*T)->Left) /* 有左孩子 */
DestroyBiTree(&(*T)->Left); /* 销毁左孩子子树 */
if((*T)->Right) /* 有右孩子 */
DestroyBiTree(&(*T)->Right); /* 销毁右孩子子树 */
free(*T); /* 释放根结点 */
*T=NULL; /* 空指针赋0 */
}

}



void PreOrderTraversalBiTree(BinTree T)   //先序遍历二叉树
{
    if (T == NULL)
    {
        return;
    }
    else
    {
        printf("%d ",T->Data);
        PreOrderTraversalBiTree(T->Left);
        PreOrderTraversalBiTree(T->Right);
    }
}


void MiddleOrderTraversalBiTree(BinTree T)  //中序遍历二叉树
{
    if (T == NULL)
    {
        return;
    }
    else
    {
    
        MiddleOrderTraversalBiTree(T->Left);
          printf("%d ",T->Data);
        MiddleOrderTraversalBiTree(T->Right);
    }
}


void PostOrderTraversaBiTree(BinTree T)   //后续遍历二叉树
{
    if (T == NULL)
    {
        return;
    }
    else
    {
       PostOrderTraversaBiTree(T->Left);
        
    PostOrderTraversaBiTree(T->Right);
          printf("%d ",T->Data);
    }
}


int TreeDeep( BinTree T)  //二叉树的深度
{
    int deep = 0;
    if (T != NULL)
    {
        int leftdeep = TreeDeep(T->Left);
        int rightdeep = TreeDeep(T->Right);
        deep = leftdeep >= rightdeep?leftdeep+1:rightdeep+1;
    }

    return deep;
}


int LeafCount(BinTree T)  //叶子节点个数
{
    static int count;
    if (T != NULL)
    {
        if (T->Left == NULL && T->Right == NULL)
        {
             count++;
        }

        LeafCount(T->Left);
        LeafCount(T->Right);
    }

    return count;
}

//主函数
int main(int argc,const char *argv[])
{
    BinTree T;
    int depth,leafCount = 0;
    printf("请输入第一个节点的值,-1表示没有叶节点:\n");
    CreateBinTree(&T);

    printf("先序遍历二叉树:");
    PreOrderTraversalBiTree(T);
    printf("\n");

    printf("中序遍历二叉树:");
    MiddleOrderTraversalBiTree(T);
    printf("\n");

    printf("后续遍历二叉树:");
    PostOrderTraversaBiTree(T);
    printf("\n");

    depth = TreeDeep(T);
    printf("树的深度为:%d\n",depth);
    
    leafCount = LeafCount(T);
    printf("叶子节点个数:%d\n",leafCount);

   DestroyBiTree(&T);   //销毁一个树
 
 
   
    return 0;
}

3、二叉树搜索树

3.1、二叉搜索树的概念

二叉查找树(Binary Search Tree):(二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

3.2、二叉搜索树的原理

二叉搜索树(BST)又称二叉查找树或二叉排序树。一棵二叉搜索树是以二叉树来组织的,可以使用一个链表数据结构来表示,其中每一个结点就是一个对象。一般地,除了key和位置数据之外,每个结点还包含属性lchild、rchild和parent,分别指向结点的左孩子、右孩子和双亲(父结点)。如果某个孩子结点或父结点不存在,则相应属性的值为空(NIL)。根结点是树中唯一父指针为NULL的结点,而叶子结点的孩子结点指针也为NULL。

3.3、二叉搜索树的性质

1.若任意结点的左子树不空,则左子树上所有结点的值均不大于它的根结点的值。
2. 若任意结点的右子树不空,则右子树上所有结点的值均不小于它的根结点的值。
3.任意结点的左、右子树也分别为二叉搜索树

3.4、二叉搜索树的操作
3.4.1、二叉搜索树的数据结构
 typedef  int ElemenType;
  typedef struct TreeNode {
     struct TreeNode *Left;    //指向左子树 
     struct TreeNode *Right;  //指向右子树 
     ElemenType data;       
     int level;

 }TreeNode, *BinTree;
3.4.2、二叉搜索树的初始化
 int initTree(BinTree *T){   //初始化搜索二叉树 
     *T = NULL;
     return 0;
 }
3.4.3、查找指定值并放回地址
 BinTree Find(ElemenType X,BinTree BST)   //二叉树搜索指定的值 
 {
 	if(!BST)
 	{
 		return 	NULL;    //查找失败 
	 }
	 if(X > BST->data) 
	 {
	 	return Find(X,BST->Right);
	 }
	 else if(X < BST->data)
	 {
	  	return Find(X,BST->Left);
	 }
	 else
	 {
	 	return BST;
	 }
 }
3.4.4、查找树的最小值
 BinTree FindMin(BinTree BST)    //查找最小值 
 {
 		if(!BST)
 	{
 		return 	NULL;    //查找失败 
	 }
	 else if(!BST->Left) 
	 {
	 	return BST;
	 }
	 else
	  return FindMin(BST->Left);
 }
 
3.4.5、查找树的最大值
 BinTree FindMax(BinTree BST)    //查找最大值 
 {
 	if(BST)
 	{
 	while(BST->Right) 
 	{
 	BST=BST->Right;	
	 }
	 }

	  return BST;
 }
3.4.6、二叉搜索树的值插入
  void insertNode(BinTree *T,int value,int level){   //搜索二叉树的插入 
     level ++;

      if (*T == NULL){
         // 树为空时
         *T = malloc(sizeof(TreeNode));

          if (*T  != NULL){
             (*T)->data = value;
             (*T)->Left = NULL;
             (*T)->Right = NULL;
             (*T)->level = level;
             //printf("Insert value: %d success, lelevl:%d\n",value,level-1);
             //return 0;
         } else{
             printf("error occured\n");

          }

      }
     else{
         // 树不为空

          // 插入到左子树
         if(value < (*T)->data){
             insertNode(&(*T)->Left,value,level);
         }
         else{
             // 插入右子树
             if (value > (*T)->data){
                 insertNode(&(*T)->Right,value,level);
             }
             else {
  
                 printf("结点已存在 值域: %d; 层数:%d", (*T)->data,(*T)->level);
           
             }

          }

      }

  }
3.4.7、二叉搜索树的删除
BinTree Delete( BinTree BST, ElemenType X ) 
{ 
    BinTree Tmp; 

    if( !BST ) 
        printf("要删除的元素未找到"); 
    else {
        if( X < BST->data ) 
            BST->Left = Delete( BST->Left, X );   /* 从左子树递归删除 */
        else if( X > BST->data ) 
            BST->Right = Delete( BST->Right, X ); /* 从右子树递归删除 */
        else { /* BST就是要删除的结点 */
            /* 如果被删除结点有左右两个子结点 */ 
            if( BST->Left && BST->Right ) {
                /* 从右子树中找最小的元素填充删除结点 */
                Tmp = FindMin( BST->Right );
                BST->data = Tmp->data;
                /* 从右子树中删除最小元素 */
                BST->Right = Delete( BST->Right, BST->data );
            }
            else { /* 被删除结点有一个或无子结点 */
                Tmp = BST; 
                if( !BST->Left )       /* 只有右孩子或无子结点 */
                    BST = BST->Right; 
                else                   /* 只有左孩子 */
                    BST = BST->Left;
                free( Tmp );
            }
        }
    }
    return BST;
} 
3.4.7、打印二叉搜索树
 int printTree(BinTree T){
      while (T != NULL){
         printTree(T->Left);
         printf("%d ",T->data);
         printTree(T->Right);
         T = NULL;
     }
     return 0;
 }
3.4.7、完整代码
#include "stdio.h"
#include "stdlib.h"
#define MAXSIZE 50
 typedef  int ElemenType;
  typedef struct TreeNode {
     struct TreeNode *Left;    //指向左子树 
     struct TreeNode *Right;  //指向右子树 
     ElemenType data;       
     int level;

 }TreeNode, *BinTree;


  int initTree(BinTree *T){   //初始化搜索二叉树 
     *T = NULL;
     return 0;
 }
 
 BinTree Find(ElemenType X,BinTree BST)   //二叉树搜索指定的值 
 {
 	if(!BST)
 	{
 		return 	NULL;    //查找失败 
	 }
	 if(X > BST->data) 
	 {
	 	return Find(X,BST->Right);
	 }
	 else if(X < BST->data)
	 {
	  	return Find(X,BST->Left);
	 }
	 else
	 {
	 	return BST;
	 }
 }
 
 BinTree FindMin(BinTree BST)    //查找最小值 
 {
 		if(!BST)
 	{
 		return 	NULL;    //查找失败 
	 }
	 else if(!BST->Left) 
	 {
	 	return BST;
	 }
	 else
	  return FindMin(BST->Left);
 }
 
 
 
 BinTree FindMax(BinTree BST)    //查找最大值 
 {
 	if(BST)
 	{
 	while(BST->Right) 
 	{
 	BST=BST->Right;	
	 }
	 }

	  return BST;
 }
 

  void insertNode(BinTree *T,int value,int level){   //搜索二叉树的插入 
     level ++;

      if (*T == NULL){
         // 树为空时
         *T = malloc(sizeof(TreeNode));

          if (*T  != NULL){
             (*T)->data = value;
             (*T)->Left = NULL;
             (*T)->Right = NULL;
             (*T)->level = level;
             //printf("Insert value: %d success, lelevl:%d\n",value,level-1);
             //return 0;
         } else{
             printf("error occured\n");

          }

      }
     else{
         // 树不为空

          // 插入到左子树
         if(value < (*T)->data){
             insertNode(&(*T)->Left,value,level);
         }
         else{
             // 插入右子树
             if (value > (*T)->data){
                 insertNode(&(*T)->Right,value,level);
             }
             else {
  
                 printf("结点已存在 值域: %d; 层数:%d", (*T)->data,(*T)->level);
           
             }

          }

      }

  }
  
  
  
 BinTree Delete( BinTree BST, ElemenType X ) 
{ 
    BinTree Tmp; 

    if( !BST ) 
        printf("要删除的元素未找到"); 
    else {
        if( X < BST->data ) 
            BST->Left = Delete( BST->Left, X );   /* 从左子树递归删除 */
        else if( X > BST->data ) 
            BST->Right = Delete( BST->Right, X ); /* 从右子树递归删除 */
        else { /* BST就是要删除的结点 */
            /* 如果被删除结点有左右两个子结点 */ 
            if( BST->Left && BST->Right ) {
                /* 从右子树中找最小的元素填充删除结点 */
                Tmp = FindMin( BST->Right );
                BST->data = Tmp->data;
                /* 从右子树中删除最小元素 */
                BST->Right = Delete( BST->Right, BST->data );
            }
            else { /* 被删除结点有一个或无子结点 */
                Tmp = BST; 
                if( !BST->Left )       /* 只有右孩子或无子结点 */
                    BST = BST->Right; 
                else                   /* 只有左孩子 */
                    BST = BST->Left;
                free( Tmp );
            }
        }
    }
    return BST;
} 
  
  
  
  
 int printTree(BinTree T){
      while (T != NULL){
         printTree(T->Left);
         printf("%d ",T->data);
         printTree(T->Right);
         T = NULL;
     }
     return 0;
 }



  int main(){
    BinTree T = NULL;
    BinTree min,max,Finddata;
     int temp = 0;
     int i; 
     int arr[MAXSIZE] = {6,3,10,3,6,4,9,7,13,9,5};
     int len = 9;

     for ( i = 0; i < len; i++) {
         insertNode(&T,arr[i],0);  //插入 

      }
     printf("搜索二叉树构建成功\n");

      printf("请输入要插入的数字:\n");

      scanf("%d",&temp);

      insertNode(&T,temp,0);   //插入数组 
 
      printf("\n中序遍历:\n");

      printTree(T);  //打印这个二叉树 
      printf("\n"); 
      min=FindMin(T);    //寻找最小值 
      max =FindMax(T);   //寻找最大值 
      Finddata = Find(3,T);  //查找3的地址 
      
      printf("最小值%d\n",min->data) ;
     printf("最大值%d\n",max->data) ;
     printf("找到的值的地址%d,找到的地址的值为%d\n",Finddata,Finddata->data) ;
     
     Delete( T, 7 );   //删除7 
     printf("删除后的结果");
     printTree(T); //打印这个二叉树 
     
     return 0;
 }

4、平衡二叉树(AVL树)

4.1平衡二叉树的概念

平衡因子(Balance Factor,简称BT):BT(T) = Hl-Hr,其中Hl和Hr分别为T的左、右子树的高度。

平衡二叉树(Balance Binary Tree) (AVL树) 空树 或者任意节点左、右高度差的绝对值不超过1,即|BT(T)|<=1

在这里插入图片描述
给定接点水为n的AVL树的最大高度为O(log2N)。

4.2、平衡二叉树的调整(注:方框内的数值为序号,并非数值)
4.2.1、RR旋转

(注:方框内的数值为序号,并非数值)
在这里插入图片描述

不平衡的“发现者”是2,“麻烦节点” 3在发现者的右子树的右边,因而叫RR插入,需要RR旋转(右单旋)
在这里插入图片描述

4.2.2、LL旋转

(注:方框内的数值为序号,并非数值)
2“发现者”是2,“麻烦节点”5在发现者的左子树的左边,因而叫LL插入,需要LL旋转(左单旋)
在这里插入图片描述

4.2.3、LR旋转

(注:方框内的数值为序号,并非数值)在这里插入图片描述
“发现者”是1,“麻烦节点”为6,6在左子树的右边,因而叫LR插入,需要LR旋转。在这里插入图片描述

4.2.4、RL旋转

(注:方框内的数值为序号,并非数值)
在这里插入图片描述
“发现者”是5,“麻烦制造节点是”9,9在有子树的左边,因而叫RL插入,需要RL旋转

在这里插入图片描述

4.3、平衡二叉树的操作
4.3.1、平衡二叉树的数据结构
 typedef  int ElemenType;
  typedef struct TreeNode {
     struct TreeNode *Left;    //指向左子树 
     struct TreeNode *Right;  //指向右子树 
     ElemenType data;       
     int Height;

 }AVLNode,*AVLTree;
4.3.2、寻找平衡二叉树的值,返回地址
 AVLTree Find(ElemenType X,AVLTree BST)   //二叉树搜索指定的值 
 {//利用递归的思想
 	if(!BST)  
 	{ 
 		return 	NULL;    //查找失败 
	 }
	 if(X > BST->data) 
	 {
	 	return Find(X,BST->Right);
	 }
	 else if(X < BST->data)
	 {
	  	return Find(X,BST->Left);
	 }
	 else
	 {
	 	return BST;
	 }
 }
4.3.3、得到平衡二叉树的高度
int GetHeight(AVLTree root)
{
	if (root == NULL)//空树,深度为0
		return 0;
	//树的最大深度 = 左右子树中深度较大的值 + 1
	return Max(GetHeight(root->Left), GetHeight(root->Right)) + 1;
}
4.3.4、平衡二叉树LL旋转
 AVLTree SingleLeftRotation ( AVLTree A )    //LL
{ /* 注意:A必须有一个左子结点B */
  /* 将A与B做左单旋,更新A与B的高度,返回新的根结点B */     

    AVLTree B = A->Left;
    A->Left = B->Right;
    B->Right = A;
    A->Height = Max( GetHeight(A->Left), GetHeight(A->Right) ) + 1;
    B->Height = Max( GetHeight(B->Left), A->Height ) + 1;
 
    return B;
}
4.3.5、平衡二叉树RR旋转
 AVLTree SingleRightRotation ( AVLTree A )     //RR
 {
 	AVLTree B = A->Right;
 	A->Right =B->Left;
 	B->Left = A;
    A->Height = Max( GetHeight(A->Left), GetHeight(A->Right) ) + 1;
    B->Height = Max( GetHeight(B->Left), A->Height ) + 1;
 	
 	
 }
4.3.6、平衡二叉树LR旋转
 AVLTree DoubleLeftRightRotation ( AVLTree A )    //LR
{ /* 注意:A必须有一个左子结点B,且B必须有一个右子结点C */
  /* 将A、B与C做两次单旋,返回新的根结点C */
    
    /* 将B与C做右单旋,C被返回 */
    A->Left = SingleLeftRotation(A->Left);
    /* 将A与C做左单旋,C被返回 */
    return SingleLeftRotation(A);
}
4.3.7、平衡二叉树RL旋转
  AVLTree DoubleRightLeftRotation ( AVLTree A )    //rl 
{ /* 注意:A必须有一个左子结点B,且B必须有一个右子结点C */
  /* 将A、B与C做两次单旋,返回新的根结点C */
    
    /* 将B与C做右单旋,C被返回 */
    A->Right = SingleRightRotation(A->Right);
    /* 将A与C做左单旋,C被返回 */
    return SingleRightRotation(A);
}
4.3.8、平衡二叉树数据插入
 AVLTree Insert( AVLTree T, ElemenType X )
{ /* 将X插入AVL树T中,并且返回调整后的AVL树 */

    if ( !T ) { /* 若插入空树,则新建包含一个结点的树 */

        T = (AVLTree)malloc(sizeof(AVLNode));
        T->data = X;
        T->Height = 0;
        T->Left = T->Right = NULL;
     
    } /* if (插入空树) 结束 */

    else if ( X < T->data ) {
        /* 插入T的左子树 */
        T->Left = Insert( T->Left, X);
        /* 如果需要左旋 */
        if ( GetHeight(T->Left)-GetHeight(T->Right) == 2 )
            if ( X < T->Left->data ) 
               T = SingleLeftRotation(T);      /* 左单旋 */
            else 
               T = DoubleLeftRightRotation(T); /* 左-右双旋 */
    } /* else if (插入左子树) 结束 */
    
    else if ( X > T->data ) {
        /* 插入T的右子树 */
        T->Right = Insert( T->Right, X );
        /* 如果需要右旋 */
        if ( GetHeight(T->Right)-GetHeight(T->Left) == -2 )
            if ( X > T->Right->data ) 
               T = SingleRightRotation(T);     /* 右单旋 */
            else 
               T = DoubleRightLeftRotation(T); /* 右-左双旋 */
    } /* else if (插入右子树) 结束 */

    /* else X == T->Data,无须插入 */

    /* 别忘了更新树高 */
    T->Height = Max( GetHeight(T->Left), GetHeight(T->Right) ) + 1;
    
    return T;
}
4.3.9、平衡二叉树数据删除
 AVLTree Delete( AVLTree BST, ElemenType X ) 
{ 
    AVLTree Tmp; 

    if( !BST ) 
        printf("要删除的元素未找到"); 
    else {
        if( X < BST->data ) 
            BST->Left = Delete( BST->Left, X );   /* 从左子树递归删除 */
        else if( X > BST->data ) 
            BST->Right = Delete( BST->Right, X ); /* 从右子树递归删除 */
        else { /* BST就是要删除的结点 */
            /* 如果被删除结点有左右两个子结点 */ 
            if( BST->Left && BST->Right ) {
                /* 从右子树中找最小的元素填充删除结点 */
                Tmp = FindMin( BST->Right );
                BST->data = Tmp->data;
                /* 从右子树中删除最小元素 */
                BST->Right = Delete( BST->Right, BST->data );
            }
            else { /* 被删除结点有一个或无子结点 */
                Tmp = BST; 
                if( !BST->Left )       /* 只有右孩子或无子结点 */
                    BST = BST->Right; 
                else                   /* 只有左孩子 */
                    BST = BST->Left;
                free( Tmp );
            }
        }
    }
    return BST;
} 
  
4.3.10、平衡二叉树销毁
void DestroyBiTree(AVLTree *T)   //销毁一个二叉树 
{
if(*T)
{
if((*T)->Left) /* 有左孩子 */
DestroyBiTree(&(*T)->Left); /* 销毁左孩子子树 */
if((*T)->Right) /* 有右孩子 */
DestroyBiTree(&(*T)->Right); /* 销毁右孩子子树 */
free(*T); /* 释放根结点 */
*T=NULL; /* 空指针赋0 */
}
4.3.11、平衡二叉树完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


 typedef  int ElemenType;
  typedef struct TreeNode {
     struct TreeNode *Left;    //指向左子树 
     struct TreeNode *Right;  //指向右子树 
     ElemenType data;       
     int Height;

 }AVLNode,*AVLTree;


 
 AVLTree Find(ElemenType X,AVLTree BST)   //二叉树搜索指定的值 
 {
 	if(!BST)
 	{
 		return 	NULL;    //查找失败 
	 }
	 if(X > BST->data) 
	 {
	 	return Find(X,BST->Right);
	 }
	 else if(X < BST->data)
	 {
	  	return Find(X,BST->Left);
	 }
	 else
	 {
	 	return BST;
	 }
 }
 

 
 int Max(int a, int b)
{
	return a > b ? a : b;
}

AVLTree FindMin(AVLTree BST)    //查找最小值 
 {
 		if(!BST)
 	{
 		return 	NULL;    //查找失败 
	 }
	 else if(!BST->Left) 
	 {
	 	return BST;
	 }
	 else
	  return FindMin(BST->Left);
 }
 

//树的最大深度
int GetHeight(AVLTree root)
{
	if (root == NULL)//空树,深度为0
		return 0;
	//树的最大深度 = 左右子树中深度较大的值 + 1
	return Max(GetHeight(root->Left), GetHeight(root->Right)) + 1;
}

 
 AVLTree SingleLeftRotation ( AVLTree A )    //LL
{ /* 注意:A必须有一个左子结点B */
  /* 将A与B做左单旋,更新A与B的高度,返回新的根结点B */     

    AVLTree B = A->Left;
    A->Left = B->Right;
    B->Right = A;
    A->Height = Max( GetHeight(A->Left), GetHeight(A->Right) ) + 1;
    B->Height = Max( GetHeight(B->Left), A->Height ) + 1;
 
    return B;
}

 
 AVLTree SingleRightRotation ( AVLTree A )     //RR
 {
 	AVLTree B = A->Right;
 	A->Right =B->Left;
 	B->Left = A;
    A->Height = Max( GetHeight(A->Left), GetHeight(A->Right) ) + 1;
    B->Height = Max( GetHeight(B->Left), A->Height ) + 1;
 	
 	
 }
 
 
 AVLTree DoubleLeftRightRotation ( AVLTree A )    //LR
{ /* 注意:A必须有一个左子结点B,且B必须有一个右子结点C */
  /* 将A、B与C做两次单旋,返回新的根结点C */
    
    /* 将B与C做右单旋,C被返回 */
    A->Left = SingleLeftRotation(A->Left);
    /* 将A与C做左单旋,C被返回 */
    return SingleLeftRotation(A);
}

 
  AVLTree DoubleRightLeftRotation ( AVLTree A )    //rl 
{ /* 注意:A必须有一个左子结点B,且B必须有一个右子结点C */
  /* 将A、B与C做两次单旋,返回新的根结点C */
    
    /* 将B与C做右单旋,C被返回 */
    A->Right = SingleRightRotation(A->Right);
    /* 将A与C做左单旋,C被返回 */
    return SingleRightRotation(A);
}

 
 
 AVLTree Insert( AVLTree T, ElemenType X )
{ /* 将X插入AVL树T中,并且返回调整后的AVL树 */

    if ( !T ) { /* 若插入空树,则新建包含一个结点的树 */

        T = (AVLTree)malloc(sizeof(AVLNode));
        T->data = X;
        T->Height = 0;
        T->Left = T->Right = NULL;
     
    } /* if (插入空树) 结束 */

    else if ( X < T->data ) {
        /* 插入T的左子树 */
        T->Left = Insert( T->Left, X);
        /* 如果需要左旋 */
        if ( GetHeight(T->Left)-GetHeight(T->Right) == 2 )
            if ( X < T->Left->data ) 
               T = SingleLeftRotation(T);      /* 左单旋 */
            else 
               T = DoubleLeftRightRotation(T); /* 左-右双旋 */
    } /* else if (插入左子树) 结束 */
    
    else if ( X > T->data ) {
        /* 插入T的右子树 */
        T->Right = Insert( T->Right, X );
        /* 如果需要右旋 */
        if ( GetHeight(T->Right)-GetHeight(T->Left) == -2 )
            if ( X > T->Right->data ) 
               T = SingleRightRotation(T);     /* 右单旋 */
            else 
               T = DoubleRightLeftRotation(T); /* 右-左双旋 */
    } /* else if (插入右子树) 结束 */

    /* else X == T->Data,无须插入 */

    /* 别忘了更新树高 */
    T->Height = Max( GetHeight(T->Left), GetHeight(T->Right) ) + 1;
    
    return T;
}

 AVLTree Delete( AVLTree BST, ElemenType X ) 
{ 
    AVLTree Tmp; 

    if( !BST ) 
        printf("要删除的元素未找到"); 
    else {
        if( X < BST->data ) 
            BST->Left = Delete( BST->Left, X );   /* 从左子树递归删除 */
        else if( X > BST->data ) 
            BST->Right = Delete( BST->Right, X ); /* 从右子树递归删除 */
        else { /* BST就是要删除的结点 */
            /* 如果被删除结点有左右两个子结点 */ 
            if( BST->Left && BST->Right ) {
                /* 从右子树中找最小的元素填充删除结点 */
                Tmp = FindMin( BST->Right );
                BST->data = Tmp->data;
                /* 从右子树中删除最小元素 */
                BST->Right = Delete( BST->Right, BST->data );
            }
            else { /* 被删除结点有一个或无子结点 */
                Tmp = BST; 
                if( !BST->Left )       /* 只有右孩子或无子结点 */
                    BST = BST->Right; 
                else                   /* 只有左孩子 */
                    BST = BST->Left;
                free( Tmp );
            }
        }
    }
    return BST;
} 
  
	
void DestroyBiTree(AVLTree *T)   //销毁一个二叉树 
{
	if(*T)
	{
	if((*T)->Left) /* 有左孩子 */
	DestroyBiTree(&(*T)->Left); /* 销毁左孩子子树 */
	if((*T)->Right) /* 有右孩子 */
	DestroyBiTree(&(*T)->Right); /* 销毁右孩子子树 */
	free(*T); /* 释放根结点 */
	*T=NULL; /* 空指针赋0 */
	}
	
}
   
 int printTree(AVLTree T){
      while (T != NULL){
         printTree(T->Left);
       
         printf("%d ",T->data);
         printTree(T->Right);
         T = NULL;
     }
    
     return 0;
 }



  int main(){
    AVLTree T = NULL,Temp;
    AVLTree Finddata;
     int temp = 0;
    int arr[] = {3,6,4,9,7,13,5,12,1};
     int i;
	     int len = (int) sizeof(arr) / sizeof(*arr);

     for ( i = 0; i < len; i++) {
         T= Insert(T,arr[i]);   //插入 

      }
      
  

     printTree(T);  //打印这个二叉树 
     printf("\n"); 
     printf("该二叉树的高度为:");
     printf("%d",GetHeight(T)); 
     
     
      Temp =Find(6,T);   //寻找值  返回地址 
      printf("寻找值的地址为%x,值为%d\n",Temp,Temp->data); 
      printf("\n中序遍历:\n");

     Delete(T,5); 
     printf("删除的值为5\n");
     printTree(T); 
     printf("\n"); 
     DestroyBiTree(&T);
     printf("销毁成功\n");
         printTree(T); 
     return 0;
 }

5、哈夫曼树(WPL)的实现

5.1、哈夫曼树的定义

给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

5.2、哈夫曼树的术语

1、路径和路径长度
在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。

2、结点的权及带权路径长度
若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。

3、树的带权路径长度
树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL。

5.2、哈夫曼树的特点

1.没有度为1的节点。
n个叶子节点的哈夫曼树共有2n-1个节点;
哈夫曼树的任意非叶节点的左右子树交换后仍然是哈夫曼树。

5.3、哈夫曼树用于编码

用二叉树进行编码:
1.左右分支:0、1;
2.字符只在叶子节点上

5.4、哈夫曼树创建
void CreateHuffmanTree(HuffmanTree *HT, ElemenType *w, ElemenType n)
{   int i,m; 
    if(n<=1) return; 
     m = 2*n-1; 
    *HT = (HuffmanTree) malloc((m+1) * sizeof(HTNode)); // 0号位置不用
    HuffmanTree p = *HT;
    for(i = 1; i <= n; i++)
    {
        (p+i)->weight = *(w+i-1);
        (p+i)->parent = 0;
        (p+i)->left = 0;
        (p+i)->right = 0;
    }
    for( i = n+1; i <= m; i++)
    {
        (p+i)->weight = 0;
        (p+i)->parent = 0;
        (p+i)->left = 0;
        (p+i)->right = 0;
    }
    //构建哈夫曼树
    for( i = n+1; i <= m; i++)
    {
        int s1, s2;
        Select(*HT, i-1, &s1, &s2);
        (*HT)[s1].parent = (*HT)[s2].parent = i;
        (*HT)[i].left = s1;
        (*HT)[i].right = s2;
        (*HT)[i].weight = (*HT)[s1].weight + (*HT)[s2].weight;
    }
}
5.5、哈夫曼树的编码
void HuffmanCoding(HuffmanTree HT, HuffmanCode *HC,ElemenType n){
	int i,start,c,j;
    *HC = (HuffmanCode) malloc((n+1) * sizeof(char *));
    char *cd = (char *)malloc(n*sizeof(char)); //存放结点哈夫曼编码的字符串数组
    cd[n-1] = '\0';//字符串结束符
   
    for( i=1; i<=n; i++){
       start = n-1;
       c = i;
        j = HT[i].parent;
        while(j != 0){
            if(HT[j].left == c)
                cd[--start] = '0';
            else
                cd[--start] = '1';
     
            c = j;
            j = HT[j].parent;
        }
        (*HC)[i] = (char *)malloc((n-start)*sizeof(char));
        strcpy((*HC)[i], &cd[start]);
    }

    free(cd);
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梨花落-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值