C语言 数据结构平衡二叉树实例详解

数据结构平衡二叉树

参考代码如下:


/*
  名称:平衡二叉树
  语言:数据结构C语言版
  编译环境:VC++ 6.0
  日期: 2014-3-26
*/
#include <stdio.h>
#include <malloc.h>
#include <windows.h>
#define LH +1  // 左高
#define EH 0  // 等高
#define RH -1  // 右高
#define N 5   // 数据元素个数  

typedef char KeyType; // 设关键字域为字符型  

typedef struct
{
  KeyType key;
  int order;
}ElemType; // 数据元素类型  

// 平衡二叉树的类型
typedef struct BSTNode
{
  ElemType data;
  // bf结点的平衡因子,只能够取0,-1,1,它是左子树的深度减去
  // 右子树的深度得到的
  int bf;
  struct BSTNode *lchild,*rchild; // 左、右孩子指针
}BSTNode,*BSTree; 

// 构造一个空的动态查找表DT
int InitDSTable(BSTree *DT)
{
  *DT=NULL;
  return 1;
} 

// 销毁动态查找表DT
void DestroyDSTable(BSTree *DT)
{
  if(*DT) // 非空树
  {
    if((*DT)->lchild) // 有左孩子
      DestroyDSTable(&(*DT)->lchild); // 销毁左孩子子树
    if((*DT)->rchild) // 有右孩子
      DestroyDSTable(&(*DT)->rchild); // 销毁右孩子子树
    free(*DT); // 释放根结点
    *DT=NULL; // 空指针赋0
  }
} 

// 在根指针T所指二叉排序树中递归地查找某关键字等于key的数据元素,
// 若查找成功,则返回指向该数据元素结点的指针,否则返回空指针。
BSTree SearchBST(BSTree T,KeyType key)
{
  if((!T)|| (key == T->data.key))
    return T; // 查找结束
  else if(key < T->data.key) // 在左子树中继续查找
    return SearchBST(T->lchild,key);
  else
    return SearchBST(T->rchild,key); // 在右子树中继续查找
} 

// 对以*p为根的二叉排序树作右旋处理,处理之后p指向新的树根结点,即旋转
// 处理之前的左子树的根结点。
void R_Rotate(BSTree *p)
{
  BSTree lc;
  lc=(*p)->lchild; // lc指向p的左子树根结点
  (*p)->lchild=lc->rchild; // lc的右子树挂接为p的左子树
  lc->rchild=*p;
  *p=lc; // p指向新的根结点
} 

// 对以*p为根的二叉排序树作左旋处理,处理之后p指向新的树根结点,即旋转
// 处理之前的右子树的根结点。
void L_Rotate(BSTree *p)
{
  BSTree rc;
  rc=(*p)->rchild; // rc指向p的右子树根结点
  (*p)->rchild=rc->lchild; // rc的左子树挂接为p的右子树
  rc->lchild=*p;
  *p=rc; // p指向新的根结点
} 

// 对以指针T所指结点为根的二叉树作左平衡旋转处理,本算法结束时,
// 指针T指向新的根结点。
void LeftBalance(BSTree *T)
{
  BSTree lc,rd;
  lc=(*T)->lchild; // lc指向*T的左子树根结点
  switch(lc->bf)
  { // 检查*T的左子树的平衡度,并作相应平衡处理
  case LH: // 新结点插入在*T的左孩子的左子树上,要作单右旋处理
    (*T)->bf=lc->bf=EH;
    R_Rotate(T);
    break;
  case RH: // 新结点插入在*T的左孩子的右子树上,要作双旋处理
    rd=lc->rchild; // rd指向*T的左孩子的右子树根
    switch(rd->bf)
    { // 修改*T及其左孩子的平衡因子
    case LH:
      (*T)->bf=RH;
      lc->bf=EH;
      break;
    case EH:
      (*T)->bf=lc->bf=EH;
      break;
    case RH:
      (*T)->bf=EH;
      lc->bf=LH;
    }
    rd->bf=EH;
    L_Rotate(&(*T)->lchild); // 对*T的左子树作左旋平衡处理
    R_Rotate(T); // 对*T作右旋平衡处理
  }
} 

// 对以指针T所指结点为根的二叉树作右平衡旋转处理,本算法结束时,
// 指针T指向新的根结点
void RightBalance(BSTree *T)
{
  BSTree rc,rd;
  rc=(*T)->rchild; // rc指向*T的右子树根结点
  switch(rc->bf)
  { // 检查*T的右子树的平衡度,并作相应平衡处理
  case RH: // 新结点插入在*T的右孩子的右子树上,要作单左旋处理
    (*T)->bf=rc->bf=EH;
    L_Rotate(T);
    break;
  case LH: // 新结点插入在*T的右孩子的左子树上,要作双旋处理
    rd=rc->lchild; // rd指向*T的右孩子的左子树根
    switch(rd->bf)
    { // 修改*T及其右孩子的平衡因子
    case RH: (*T)->bf=LH;
      rc->bf=EH;
      break;
    case EH: (*T)->bf=rc->bf=EH;
      break;
    case LH: (*T)->bf=EH;
      rc->bf=RH;
    }
    rd->bf=EH;
    R_Rotate(&(*T)->rchild); // 对*T的右子树作右旋平衡处理
    L_Rotate(T); // 对*T作左旋平衡处理
  }
} 

// 若在平衡的二叉排序树T中不存在和e有相同关键字的结点,则插入一个
// 数据元素为e的新结点,并返回1,否则返回0。若因插入而使二叉排序树
// 失去平衡,则作平衡旋转处理,布尔变量taller反映T长高与否。
int InsertAVL(BSTree *T,ElemType e,int *taller)
{
  if(!*T)
  { // 插入新结点,树“长高”,置taller为1
    *T=(BSTree)malloc(sizeof(BSTNode));
    (*T)->data=e;
    (*T)->lchild=(*T)->rchild=NULL;
    (*T)->bf=EH;
    *taller=1;
  }
  else
  {
    if(e.key == (*T)->data.key)
    { // 树中已存在和e有相同关键字的结点则不再插入
      *taller=0;
      return 0;
    }
    if(e.key < (*T)->data.key)
    { // 应继续在*T的左子树中进行搜索
      if(!InsertAVL(&(*T)->lchild,e,taller)) // 未插入
        return 0;
      if(*taller)
        // 已插入到*T的左子树中且左子树“长高”
        switch((*T)->bf) // 检查*T的平衡度
        {
        case LH:
          // 原本左子树比右子树高,需要作左平衡处理
          LeftBalance(T);
          *taller=0; //标志没长高
          break;
        case EH:
          // 原本左、右子树等高,现因左子树增高而使树增高
          (*T)->bf=LH;
          *taller=1; //标志长高
          break;
        case RH:
          // 原本右子树比左子树高,现左、右子树等高
          (*T)->bf=EH;
          *taller=0; //标志没长高
      }
    }
    else
    {
      // 应继续在*T的右子树中进行搜索
      if(!InsertAVL(&(*T)->rchild,e,taller)) // 未插入
        return 0;
      if(*taller) // 已插入到T的右子树且右子树“长高”
        switch((*T)->bf) // 检查T的平衡度
      {
      case LH:
        (*T)->bf=EH; // 原本左子树比右子树高,现左、右子树等高
        *taller=0;
        break;
      case EH: // 原本左、右子树等高,现因右子树增高而使树增高
        (*T)->bf=RH;
        *taller=1;
        break;
      case RH: // 原本右子树比左子树高,需要作右平衡处理
        RightBalance(T);
        *taller=0;
      }
    }
  }
  return 1;
} 

// 按关键字的顺序对DT的每个结点调用函数Visit()一次
void TraverseDSTable(BSTree DT,void(*Visit)(ElemType))
{
  if(DT)
  {
    TraverseDSTable(DT->lchild,Visit); // 先中序遍历左子树
    Visit(DT->data); // 再访问根结点
    TraverseDSTable(DT->rchild,Visit); // 最后中序遍历右子树
  }
} 

void print(ElemType c)
{
  printf("(%d,%d)",c.key,c.order);
} 

int main()
{
  BSTree dt,p;
  int k;
  int i;
  KeyType j;
  ElemType r[N]={
    {13,1},{24,2},{37,3},{90,4},{53,5}
  }; // (以教科书P234图9.12为例)  

  InitDSTable(&dt);  // 初始化空树
  for(i=0;i<N;i++)
    InsertAVL(&dt,r[i],&k); // 建平衡二叉树
  TraverseDSTable(dt,print); // 按关键字顺序遍历二叉树
  printf("\n请输入待查找的关键字: ");
  scanf("%d",&j);
  p=SearchBST(dt,j); // 查找给定关键字的记录
  if(p)
    print(p->data);
  else
    printf("表中不存在此值");
  printf("\n");
  DestroyDSTable(&dt); 

  system("pause");
  return 0;
}
/*
输出效果: 

(13,1)(24,2)(37,3)(53,5)(90,4)
请输入待查找的关键字: 53
(53,5)
请按任意键继续. . .  

*/

运行结果如下:

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • 使用C语言构建基本的二叉树数据结构

    二叉树结构常用的一些初始化代码 #include #include typedef struct Node{ int data; Node *leftchild; Node *rightchild; }Node; /* 初始化一棵二叉树排序树. */ void InitBinaryTree(Node**root,int elem) { *root=(Node*)malloc(sizeof(Node)); if(!(*root)) { printf("Memory allocation for r

  • C语言数据结构二叉树简单应用

     C语言数据结构二叉树简单应用 在计算机科学中,二叉树是每个节点最多有两个子树的树结构.通常子树被称作"左子树"(left subtree)和"右子树"(right subtree),接下来我就在这里给大家介绍一下二叉树在算法中的简单使用: 我们要完成总共有 (1)二叉树的创建 (2)二叉树的先中后序递归遍历 (3)统计叶子结点的总数 (4)求树的高度 (5)反转二叉树 (6)输出每个叶子结点到根节点的路径 (7)输出根结点到每个叶子结点的路径. 定义二叉树结点类型

  • c语言版本二叉树基本操作示例(先序 递归 非递归)

    复制代码 代码如下: 请按先序遍历输入二叉树元素(每个结点一个字符,空结点为'='):ABD==E==CF==G== 先序递归遍历:A B D E C F G中序递归遍历:D B E A F C G后序递归遍历:D E B F G C A层序递归遍历:ABCDEFG先序非递归遍历:A B D E C F G中序非递归遍历:D B E A F C G后序非递归遍历:D E B F G C A深度:请按任意键继续. . . 复制代码 代码如下: #include<stdio.h>#include&

  • C语言实现二叉树的搜索及相关算法示例

    本文实例讲述了C语言实现二叉树的搜索及相关算法.分享给大家供大家参考,具体如下: 二叉树(二叉查找树)是这样一类的树,父节点的左边孩子的key都小于它,右边孩子的key都大于它. 二叉树在查找和存储中通常能保持logn的查找.插入.删除,以及前驱.后继,最大值,最小值复杂度,并且不占用额外的空间. 这里演示二叉树的搜索及相关算法: #include<stack> #include<queue> using namespace std; class tree_node{ public

  • 举例讲解C语言程序中对二叉树数据结构的各种遍历方式

    二叉树遍历的基本思想 二叉树的遍历本质上其实就是入栈出栈的问题,递归算法简单且容易理解,但是效率始终是个问题.非递归算法可以清楚的知道每步实现的细节,但是乍一看不想递归算法那么好理解,各有各的好处吧.接下来根据下图讲讲树的遍历. 1.先序遍历:先序遍历是先输出根节点,再输出左子树,最后输出右子树.上图的先序遍历结果就是:ABCDEF 2.中序遍历:中序遍历是先输出左子树,再输出根节点,最后输出右子树.上图的中序遍历结果就是:CBDAEF 3.后序遍历:后序遍历是先输出左子树,再输出右子树,最后输

  • C语言 二叉树的链式存储实例

    二叉树的链式存储 实现二叉树的基本操作:建立.遍历.计算深度.结点数.叶子数等. 输入C,先序创建二叉树,#表示空节点: 输入H:计算二叉树的高度: 输入L:计算二叉树的叶子个数: 输入N:计算二叉树节点总个数: 输入1:先序遍历二叉树: 输入2:中序遍历二叉树: 输入3:后续遍历二叉树: 输入F:查找值=x的节点的个数: 输入P:以缩格文本形式输出所有节点. 很简单就不需要多解释了,代码贴上 #include <stdio.h> #include <stdlib.h> #incl

  • C语言中计算二叉树的宽度的两种方式

    C语言中计算二叉树的宽度的两种方式 二叉树作为一种很特殊的数据结构,功能上有很大的作用!今天就来看看怎么计算一个二叉树的最大的宽度吧. 采用递归方式 下面是代码内容: int GetMaxWidth(BinaryTree pointer){ int width[10];//加入这棵树的最大高度不超过10 int maxWidth=0; int floor=1; if(pointer){ if(floor==1){//如果访问的是根节点的话,第一层节点++; width[floor]++; flo

  • C语言实现线索二叉树的定义与遍历示例

    本文实例讲述了C语言实现线索二叉树的定义与遍历.分享给大家供大家参考,具体如下: #include <stdio.h> #include <malloc.h> typedef char TElemType; // 二叉树的二叉线索存储表示 typedef enum{ Link, Thread }PointerTag; // Link(0):指针,Thread(1):线索 typedef struct BiThrNode { TElemType data; struct BiThrN

  • C语言 数据结构平衡二叉树实例详解

    数据结构平衡二叉树 参考代码如下: /* 名称:平衡二叉树 语言:数据结构C语言版 编译环境:VC++ 6.0 日期: 2014-3-26 */ #include <stdio.h> #include <malloc.h> #include <windows.h> #define LH +1 // 左高 #define EH 0 // 等高 #define RH -1 // 右高 #define N 5 // 数据元素个数 typedef char KeyType; /

  • C语言数据结构 快速排序实例详解

    C语言数据结构 快速排序实例详解 一.快速排序简介 快速排序采用分治的思想,第一趟先将一串数字分为两部分,第一部分的数值都比第二部分要小,然后按照这种方法,依次对两边的数据进行排序. 二.代码实现 #include <stdio.h> /* 将两个数据交换 */ void swap(int* Ina , int* Inb) { int temp = *Ina; *Ina = *Inb; *Inb = temp; } /* 进行一趟的快速排序,把一个序列分为两个部分 */ int getPart

  • Linux 下C语言连接mysql实例详解

    Linux 下C语言连接mysql实例详解 第一步: 安装mysql, 参考:http://www.jb51.net/article/39190.htm 第二步: 安装mysql.h函数库 sudo apt-get install libmysqlclient-dev 执行之后就可以看到/usr/include/MySQL目录了 然后开始我们的链接. 首先看我的数据库 mysql> show databases; +--------------------+ | Database | +----

  • C语言文件复制实例详解

    C语言文件复制实例详解 文件复制,在Linux中,将生成的read.o 重新文件拷贝一份复制到ReadCopy.o中,并且更改ReadCopy.o文件的操作权限.使其能够正常运行. 实例代码: #include <stdio.h> int main(){ FILE *r_file = fopen ("read.o","rb"); FILE *w_file = fopen ("ReadCopy.o","w"); ch

  • C语言柔性数组实例详解

    本文实例分析了C语言柔性数组的概念及用法,对于进一步学习C程序设计有一定的借鉴价值.分享给大家供大家参考.具体如下: 一般来说,结构中最后一个元素允许是未知大小的数组,这个数组就是柔性数组.但结构中的柔性数组前面必须至少一个其他成员,柔性数组成员允许结构中包含一个大小可变的数组,sizeof返回的这种结构大小不包括柔性数组的内存.包含柔数组成员的结构用malloc函数进行内存的动态分配,且分配的内存应该大于结构的大小以适应柔性数组的预期大小.柔性数组到底如何使用? 不完整类型 C和C++对于不完

  • R语言关于卡方检验实例详解

    卡方检验是一种确定两个分类变量之间是否存在显着相关性的统计方法. 这两个变量应该来自相同的人口,他们应该是类似 是/否,男/女,红/绿等. 例如,我们可以建立一个观察人们的冰淇淋购买模式的数据集,并尝试将一个人的性别与他们喜欢的冰淇淋的味道相关联. 如果发现相关性,我们可以通过了解访问的人的性别的数量来计划适当的味道库存. 语法 用于执行卡方检验的函数是chisq.test(). 在R语言中创建卡方检验的基本语法是 chisq.test(data) 以下是所使用的参数的描述 data是以包含观察

  • C语言数据结构之堆排序详解

    目录 1.堆的概念及结构 2.堆的实现 2.1堆的向下调整算法 2.2堆的向上调整算法 2.3建堆(数组) 2.4堆排序 2.5堆排序的时间复杂度 1.堆的概念及结构 如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树(二叉树具体概念参见——二叉树详解)的顺序存储方式存储在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为小堆(或大

  • C语言数据结构之二叉树详解

    目录 1. 树概念及结构 1.1树概念 1.2树的表示 2. 二叉树概念及结构 2.1概念 2.2数据结构中的二叉树 2.3特殊的二叉树 2.4二叉树的存储结构 2.5二叉树的性质 3. 二叉树顺序结构及概念 3.1二叉树的顺序结构 3.2堆的概念及结构 3.3堆的实现 4. 二叉树链式结构及实现 4.1二叉树链式结构的遍历 4.2二叉树的链式实现 1. 树概念及结构 1.1树概念 树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合.把它叫做树是因为它看起来像一棵

  • C语言关系运算符实例详解

    在程序中经常需要比较两个数据的大小,以决定程序下一步的工作.比如一个程序限制了只能成年人使用,儿童因为年龄不够,没有权限使用.这时候程序就需要获取用户输入的年龄并做出判断,如果超过18岁就正常运行,否则给出无权使用的提示. 比较两个数据大小的运算符称为关系运算符(Relational Operators). 在C语言中有以下关系运算符: 1) <(小于) 2) <=(小于或等于) 3) >(大于) 4) >=(大于或等于) 5) ==(等于) 6) !=(不等于) 关系运算符都是双

  • C语言内存对齐实例详解

    本文详细讲述了C语言程序设计中内存对其的概念与用法.分享给大家供大家参考之用.具体如下: 一.字节对齐基本概念 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同.一些平台对某些特定类型的数据只能从某些特定地址开始存取.比如有些架构的C

随机推荐