树(C语言)

判定树

每个结点需要查找的次数刚好为该结点所在的层数,查找成功时查找次数不会超过判定树的深度,n个结点的判定树的深度为[LgN]+1

平均查找长度ASL(Average Search Length)
ASL=sum(层数*个数)/各层总个数n(n>=0)个结点构成的有限集合当n=0时称为空树

对于任何一棵非空树(n>0),它具备以下性质

  • 树中会有一个root特殊结点用r表示
  • 其余结点可分为m(m>0)个互不相交的有限集,其中每个集合本身又是一棵树,称为原来树的子树

树的特点:

  • 子树是不相交的
  • 出了根节点外,每隔结点有且仅有一个父结点
  • 一棵N个结点的树有N-1条边(树是保证结点连通的最少边链接方式)

树的一些基本术语:

  • 结点的度:结点的子树个数(满二叉树单个结点的度为2)

  • 树的度:树的所有结点中最大的度数

  • 叶结点:结点度为0的结点

  • 父节点,子节点,兄弟结点

  • 路径和路径长度

  • 祖先节点:沿树根到某一结点路径上的所有节点都是这个结点的祖先结点
    子孙结点通;

  • 结点的层次:规定根结点在一层,其他层次随子节点+1

  • 树的深度:树中结点的最大层次就是这棵树的深度

    儿子兄弟表示法可以将所有的树转化为二叉树
    特殊二叉树:

  • 斜二叉树:只有左儿子或只有右结点

  • 完美二叉树:满二叉树

  • 完全二叉树:结点编号与满二叉树结点编号相同(编号不间断)
    二叉树的特点

  • 一个二叉树第i层的最大节点数为:2(i-1),i>=1

  • 深度为k的二叉树有最大节点总数为2k-1,k>=1;

  • 对于任何非空二叉树T,若N0表示叶子结点的个数,N2是度为2的非叶结点个数,那么两者满足关系:N0=N2+1;(即叶子结点个数-1=度数为2的结点个数)

二叉树的抽象数据类型定义
数据对象集:一个有穷的结点集合
若不为空,则由根节点和其左、右二叉树组成
操作集:判断树是否为空,遍历,创建二叉树

常用的遍历方法有:
先序遍历(根左右),
中序遍历(左根右),
后序遍历(左右根),
层次遍历(从上到下,从左到右)

在二叉树中,我们知道叶结点总数n0与有两个儿子的结点总数n2之间的关系是:n0=n2+1.
那么类似关系是否可以推广到m叉树中?也就是,如果在m叉树中,叶结点总数是n0,
有一个儿子的结点总数是n1,有2个儿子的结点总数是n2,有3个儿子的结点总数是n3,
那么,ni之间存在什么关系?

  • 完全二叉树,非根节点的父节点序号是[i/2]
  • 结点的左孩子结点序号是2i,若2i<=n,否则没有左孩子结点
  • 结点的右孩子结点序号是2i+1,(若2i+1<=n,否则没有右孩子)
 typedef struct BT{
     int value;
     struct BT *leftchild;
     struct BT *rightchild;
 }BinTree;
 //二叉树的每个结点遍历都会遇到三次,第一次遇到就打印的为先序遍历,第二次遇到就打印的为中序遍历,第三次遇到就打印的为后序遍历
 //先序遍历(递归遍历)
 void PreOrderTraversal(BinTree *BT){
     if(BT){
     if(!BT->leftchild&&!BT->rightchild)
         printf("%d\n",BT->value);
         PreOrderTraversal(BT->leftchild);
         PreOrderTraversal(BT->rightchild);
     }
 }
 //中序遍历(递归遍历)
 void InOrderTraversal(BinTree *BT){
     if(BT){
     if(!BT->leftchild&&!BT->rightchild)
         InOrderTraversal(BT->leftchild);
         printf("%d\n",BT->value);
         InOrderTraversal(BT->rightchild);
     }
 }
 //后序遍历(递归遍历)
 void PostOrderTraversal(BinTree *BT){
     if(BT){
     if(!BT->leftchild&&!BT->rightchild)
         PostOrderTraversal(BT->leftchild);
         PostOrderTraversal(BT->rightchild);
         printf("%d\n",BT->value);
     }
 }
 //二叉树遍历的本质是将二维序列转换为一维序列
 //使用队列进行二叉树的层级访问(遍历根节点,将左右儿子节点入队列)
 void LevelOrderTraversal(BinTree BT){
     Queue *queue;
     BinTree *T;
     queue=CreateQueue();
     AddQueue(queue,BT);
     while(!IsEmptyQueue(queue)){
         T=DeleteQueue(queue);
         printf("%d\n",T->value);
         if(T->leftchild)AddQueue(queue,T->leftchild);
         if(T->rightchild)AddQueue(queue,T->rightchild);
     }
 }
 //给定前中序遍历结果或中后序遍历结果可以唯一确定一棵二叉树,给定前后序遍历结果不能唯一确定二叉树
 //非递归实现(中序遍历)
 void InOrderTraversal(BinTree *BT){
     BinTree *T=BT;
     LinkedStack *stack=CreateLinkedStack();//创建并初始化堆栈
     while(T||!isEmpty(stack)){
         while(T){//一直向左将沿途结点压入堆栈
             Push(stack,T);
             T=T->leftchild;//转向左子树
         }
         if(!isEmpty(stack)){
             T=Pop(stack);//结点弹出堆栈
             printf("%5d",T->value);//打印结点
             T=T->rightchild;//转向右子树
         }
     }
 }
 //非递归实现(先序遍历)
 void PreOrderTraversal(BinTree *BT){
     BinTree *T=BT;
     LinkedStack *stack=CreateLinkedStack();//创建并初始化堆栈
     while(T||!isEmpty(stack)){
         while(T){//一直向左将沿途结点压入堆栈
             printf("%5d",T->value);//打印结点
             Push(stack,T);
             T=T->leftchild;//转向左子树
         }
         if(!isEmpty(stack)){
             T=Pop(stack);//结点弹出堆栈
             T=T->rightchild;//转向右子树
         }
     }
 }
二叉搜索树:BST(binary search tree)

也称二叉排序树或二叉查找树
二叉搜索树条件
1.非空左子树的所有键值小于其根节点的键值
2.非空右子树的所有键值大于其根节点的键值
3.左,右子树都是二叉搜索树

//递归方式实现
Position Find(BinTree *binTree,int result){
    if(!binTree)return NULL;
    if(result>binTree->value)return Find(binTree->rightchild,result);
    else if(result<binTree->value)return Find(binTree,result);
    else return binTree;//查找成功,返回结点地址(return尾递归)
}
//非递归方式实现
Position IterFind(BinTree *binTree,int value){
    while(binTree){
        if(result>binTree->value)
            binTree=binTree->rightchild;
        else if(result<binTree->value)
            binTree=binTree->leftchild;
        else 
            return binTree;
    }
    return NULL;
}
//寻找最小值
Position FindMin(BinTree *binTree){
    if(!binTree)return NULL;
    else if(!binTree->leftchild)
        return binTree;
    else
        return FindMin(binTree->leftchild);
}
//寻找最大值
Position FindMax(BinTree *binTree){
    if(binTree){
        while(binTree->rightchild)
            binTree=binTree->rightchild;
    }
    return binTree;
}
//结点插入
BinTree * Insert(BinTree *binTree, int value) {
    if(!binTree){
        binTree=malloc(sizeof(BinTree));
        binTree->value=value;
        binTree->leftchild=binTree->rightchild=NULL;
    }else{
        if(value<binTree->value)
            binTree->leftchild=Insert(binTree->leftchild,value);
        else if(value>binTree->value)
            binTree->rightchild=Insert(binTree->rightchild,value);
    }
    return binTree;
}
//删除结点
BinTree *Delete(BinTree *binTree,int value){
    (Position)BinTree *Temp;
    if(!binTree)printf("要删除的元素未找到");
        //左子树递归删除
    else if(value<binTree->value)binTree->leftchild=Delete(binTree,value);
        //右子树递归删除
    else if(value>binTree->value)binTree->rightchild=Delete(binTree->rightchild,value);
    else //找到要删除的结点
        if(binTree->leftchild&&binTree->rightchild){//被删除结点有左右量子子节点
            Temp=FindMin(binTree->rightchild);//在右子树中招最小的元素填充删除结点
            binTree->value=Temp->value;
            binTree->rightchild=Delete(binTree->rightchild,binTree->value);
        }else{//被删除的结点有一个或无子结点
            Temp=binTree;
            if(!binTree->leftchild)binTree=binTree->rightchild;
            else if(!binTree->rightchild)binTree=binTree->leftchild;
            free(Temp);
        }
    return binTree;
}
平衡二叉树(Balanced Binary Tree)

(AVL树)(AVL是提出平衡树的学者名字首字母)

  • 空树或任一结点左右子树高度差不超不过1|BF(T)|<=1
  • 平衡因子(Balance Factor 简称BF:BF(T)=Hl-Hr)
  • 其中hl和hr分别为T的左右子树高度
  • 高度=层数-1
  • 完全二叉树高度为log2N(平衡二叉树)
  • Nh是高度为h的平衡二叉树的最小结点树
  • Nh=F(h+2)-1
 #define MaxData 10000
 typedef struct HeapStruct{
     int *value;//存储对元素的数组
     int length;//堆的当前元素个数
     int capacity;//堆的最大容量
 }Heap;
优先队列(PriorityQueue)

取出元素的先后顺序是按照元素的优先权(关键字)大小,而不是元素进入队列的先后顺序
最大堆和最小堆都必须满足完全二叉树(切根节点最大或最小)最大堆的建立

建立最大堆:将已经存在的N个元素按最大堆的要求存放在要给一维数组中

  • 方法一:通过插入操作,将N个元素一个个相继插入到一个初始为空的堆中去,其时间代价最大为O(NlogN)
  • 方法二:在线性时间复杂度下建立最大堆
  • (1)将N个元素按输入顺序存入,先满足完全二叉树的结构特性
  • (2)调整各结点位置以满足最大堆的有序特性
    建堆时,最坏的情况下需要挪动的元素次数等于树中各节点的高度和

对由同样n个整数构成的二叉搜索树(查找树)和最小堆:有以下结论

  • 二叉搜索树高度大于等于最小堆高度
  • 对该二叉搜索树进行中序遍历可得到从小到大的序列
  • 从最小堆根节点到起任何叶结点的路径上的结点值构成从小到大的序列
 Heap * Create(int MaxSize){
     Heap *heap=malloc(sizeof(Heap));
     heap->value=malloc((MaxSize+1)*sizeof(int));
     heap->length=0;
     heap->capacity=MaxSize;
     heap->value[0]=MaxData;//定义哨兵,便于操作
     return heap;
 }
 void Insert(Heap *heap,int value){
     int i;
     if(IsFull(heap)){
         printf("最大堆已经满了");
         return;
     }
     i=++heap->length;
     for(;heap->value[i/2]<value;i/=2)
         heap->value[i]=heap->value[i/2];
     heap->value[i]=value;
 }
 int DeleteMax(Heap *heap){
     int parent,child;
     int maxValue,temp;
     if(IsEmpty(heap)){
         printf("最大堆已空");
         return 0;
     }
     maxValue=heap->value[1];
     //用最大堆中最后一个元素从根节点开始过滤下层结点
     temp=heap->value[heap->length--];
     for(parent=1;parent*2<=heap->length;parent=child){
         child=parent*2;
         //左儿子和右儿子节点比较取较大者
         if((child!=heap->length)&&(heap->value[child]<heap->value[child+1]))
             child++;
         if(temp>=heap->value[child])break;
         else
             heap->value[parent]=heap->value[child];
     }
     heap->value[parent]=temp;
     return maxValue;
 }
 int IsEmpty(Heap *heap){
     return heap->length==0;
 }
 int IsFull(Heap *heap){
     return heap->length==heap->capacity;
 }
 
 typedef struct TreeNode{
     int weight;
     struct TreeNode *left,*right;
 }HuffmanTree;
哈夫曼树(HuffmanTree)

查找效率,查找次数乘查找概率
带权路径长度(WPL):设二叉树有n个叶子结点,每隔叶子结点带有权值Wk,从根节点到每隔叶子结点的长度是Lk,则每隔叶子结点的带全路径长度之和WPL=(nEk=1)WkLk
最优二叉树或哈夫曼树:WPL最小的二叉树
哈夫曼树的特点

  • 没有度为1的结点
  • n个叶子结点的HuffmanTree有2n-1个结点
  • HuffmanTree的任意非叶结点的左右子树交换后仍是HuffmanTree
    对于一组权值,可能有不同构的两棵HuffmanTree
HuffmanTree *Huffman(Heap *heap){
    //假设heap->length权值已经存在heap->value[]->weight里面
    int i;HuffmanTree *huffmanTree;
    BuildHeap(heap);//将heap->value[]按权值调整为最小堆
    for(i=1;i<heap->length;i++){
        huffmanTree=malloc(sizeof(HuffmanTree));//建立新结点
        huffmanTree->left=DeleteMin(heap);//从最小堆中删除一个结点,作为新huffmanTree的左子结点
        huffmanTree->right=DeleteMin(heap);//从最小堆中删除一个结点,作为新huffmanTree的右子结点
        huffmanTree->weight=huffmanTree->weight+huffmanTree->right->weight;//计算新// 权值
        Insert(heap,huffmanTree);
    }
    huffmanTree=DeleteMin(heap);
    return huffmanTree;
}
/*二叉树用于编码
 * 当被编码字母全部在二叉树的叶子结点的时候(即,编码字母不会出现在有子节点的结点中)便可以保证字符编码没有二义性
 * */
更多关于java的文章请戳这里:(您的留言意见是对我最大的支持)

我的文章列表
Email:sxh13208803520@gmail.com

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容

  • 一、定义 有且只有1个称为根的节点;有若干个互不相交的子树,这些子树本身也是一棵树。 树由节点和边(指针域)组成。...
    3e1094b2ef7b阅读 1,025评论 1 1
  • B树的定义 一棵m阶的B树满足下列条件: 树中每个结点至多有m个孩子。 除根结点和叶子结点外,其它每个结点至少有m...
    文档随手记阅读 13,149评论 0 25
  • 1.问题描述: 1 .由已经给出的二叉树的先序(后序)和中序遍历的结果构造二叉树。遍历的结果以数组的方 式输...
    oldBook阅读 2,624评论 0 0
  • 二叉查找树,也称作二叉搜索树,有序二叉树,排序二叉树,而当一棵空树或者具有下列性质的二叉树,就可以被定义为二叉查找...
    Originalee阅读 486评论 0 2
  • 这是用手机画的。。。 因为还没点触笔。。 所以有点简陋。。
    MOMOI溟尘阅读 172评论 0 1