算法 二叉树 堆排序

树:
树是指任意两点之间有且仅有一条路径的无向图(即 不包含回路的连通无向图)
树的特点:
1.任意两点有且仅有一条路径
2.如果一个树有n个节点,那么它一定恰好有n-1条边
3.在一个树中加一条边 一定会构成回路

根节点:没有父节点的节点
叶节点:没有子节点的节点
内部节点:既不是根节点也不是叶节点的节点(即 有父亲也有儿子)

二叉树:
二叉树是每一个节点最多只有两个儿子的特殊树左边为左儿子,右边为右儿子

满二叉树:
如果二叉树中每个内部节点都有两个儿子,这样的二叉树称为满二叉树。
它的特性:如果深度为h,则节点数一定为2^h-1;

完全二叉树:若设二叉树的深度为h,则除了第h层外,其余各层(1~h-1)的节点数都达到了最大个数。第h层,
从左到右连续缺少若干节点~

如果完全二叉树的一个节点有右儿子,那它一定有左儿子。
如果完全二叉树的一个父节点为k,那它的左儿子的编号为2k,右儿子为2k+1
如果已知儿子(左儿子或右儿子)的编号为x,那它的父节点的编号为x/2

最小堆:所有父节点都比子节点小(根节点最小)
最大堆:所有父节点都比子节点大(根节点最大)


#pragma mark - - 建堆(最小堆)
/*
 方式一: 以空堆开始,每次向堆中插入一个元素,直到所有的元素插入完毕。(向上调整)时间复杂度O(NlogN)
 方式二: 一维数组可以看作成一个完全二叉树~如果二叉树中每一个节点都满足最小(大)堆,则这个完全二叉树是最小(大)堆。
 叶节点不用处理,所以只要所有非叶节点满足最小(大)堆,那这个完全二叉树是最小(大)堆~ 时间复杂度O(N)
 最后一个非叶节点是n/2
 
 */


void swap(int x,int y,int h[]) {
    int t;
    t = h[x];
    h[x] = h[y];
    h[y] = t;
    return ;
}

#pragma mark - 方式一
void siftupMin(int i,int h[]) {
    if (i==1) {
        return ;
    }
    int flag = 0; // 标示是否需要继续调整
    while (i!=1 && flag==0) {
        // 判断是否比父节点小
        // 最小堆 父节点比子节点小
        if (h[i]<h[i/2]) {
            swap(i, i/2, h);
        }else {
            flag =1;
        }
        
        i=i/2; // 更新i的编号为父节点的编号 从而方便下一次继续向上调整
    }
}


-(void)createMinHeap1{
    
    int a[15] ={0,99,2,5,12,7,17,25,19,36,1,22,28,46,92};
    int h[15];
    for (int i=1; i<=14; i++) {
        h[i] = a[i];
        siftupMin(i, h);
    }
    
    // 打印最小堆
    printf("\n");
    for (int i=1; i<=14; i++) {
        printf("%5d",h[i]);
    }
    printf("\n\n");
}

#pragma mark - 方式二
void siftdownMin(int i,int h[],int n) {
    int flag=0; // 标示是否需要继续向下调整
    int t=0; // 存储较小的编号
    // 2*i<=n 判断是否有子节点
    while (2*i<=n && flag==0) {
        // 判断左子节点是否比父节点小
        if (h[2*i]<h[i]) {
            t = 2*i;
        }else {
            t = i;
        }
        
        // 判断是否有右子节点
        if (2*i+1<=n) {
            // 判断右子节点是否比当前最小的节点小
            if (h[2*i+1]<h[t]) {
                t=2*i+1;
            }
        }
        
        // 判断i是否等于t
        if (t!=i) {
            // 交换
            swap(i, t, h);
            i = t; // 更新i为t,便于下一次的向下调整
        }else {
            flag =1;
        }
    }
    
}

-(void)createMinHeap2 {
    int h[15]={0,99,2,5,12,7,17,25,19,36,1,22,28,46,92};
    int n=14;
    
    for (int i=n/2; i>=1; i--) {
        siftdownMin(i, h, n);
    }
    
    // 打印最小堆
    printf("\n");
    for (int i=1; i<=14; i++) {
        printf("%5d",h[i]);
    }
    printf("\n\n");
}


#pragma mark - - 建堆(最大堆)
#pragma mark - 方式一
void siftupMax (int i,int h[]) {
    if (i==1) {
        return ;
    }
    int flag =0 ; // 标示是否需要向上调整
    while (i!=1 && flag==0) {
        if (h[i]>h[i/2]) {
            swap(i, i/2, h);
        }else {
            flag =1;
        }
        i= i/2; // 继续向上调整
    }
}

-(void)createMaxHeap1 {
    int a[15] ={0,99,2,5,12,7,17,25,19,36,1,22,28,46,92};
    int h[15];
    for (int i=1; i<=14; i++) {
        h[i] = a[i];
        siftupMax(i, h);
    }
    
    // 打印最大堆
    printf("\n");
    for (int i=1; i<=14; i++) {
        printf("%5d",h[i]);
    }
    printf("\n\n");
}

#pragma mark - 方式二
void siftdownMax(int i,int h[],int n) {
    int flag=0;
    int t=0; // 记录较大值的编号
    
    while (2*i<=n && flag==0) {
        if (h[2*i] > h[i]) {
            t=2*i;
        }else {
            t=i;
        }
        
        if (2*i+1<=n) {
            if (h[2*i+1] > h[t]) {
                t= 2*i+1;
            }
        }
        
        if (t!=i) {
            swap(i, t, h);
            i=t;
        }else {
            flag =1;
        }
    }
}

-(void)createMaxHeap2 {
    int h[15] ={0,99,2,5,12,7,17,25,19,36,1,22,28,46,92};
    int n=14;
    for (int i=n/2; i>=1; i--) {
        siftdownMax(i, h, n);
    }
    // 打印最大堆
    printf("\n");
    for (int i=1; i<=14; i++) {
        printf("%5d",h[i]);
    }
    printf("\n\n");
    
}

#pragma mark - - 堆排序(从小到大) O(NlogN)
// 删除顶部节点(最小堆)
// 删除顶部节点就是把最后一个节点的值赋值给顶部节点,同时n-1,并向下调整
int n;
int deleteRootMin(int h[]){
    int t;
    t=h[1];
    h[1] = h[n];
    n--;
    siftdownMin(1, h, n);
    return t;
}

-(void)heapsortMin {
    // 建堆(最小堆)
    int h[15] ={0,99,2,5,12,7,17,25,19,36,1,22,28,46,92};
    int m=14;
    n=14;
    for (int i=m/2; i>=1; i--) {
        siftdownMin(i, h, n);
    }
    
    printf("\n");
    for (int i=1; i<=m; i++) {
        printf("%5d",deleteRootMin(h));
    }
    printf("\n\n");
}

#pragma mark - - 堆排序(从大到小)
// 删除顶部节点(最大堆)
// 删除顶部节点就是把最后一个节点的值赋值给顶部节点,同时n-1,并向下调整
int deleteRootMax(int h[]){
    int t;
    t=h[1];
    h[1] = h[n];
    n--;
    siftdownMax(1, h, n);
    return t;
}

-(void)heapsortMax {
    // 建堆(最大堆)
    int h[15] ={0,99,2,5,12,7,17,25,19,36,1,22,28,46,92};
    int m=14;
    n=14;
    for (int i=m/2; i>=1; i--) {
        siftdownMax(i, h, n);
    }
    printf("\n");
    for (int i=1; i<=m; i++) {
        printf("%5d",deleteRootMax(h));
    }
    printf("\n\n");
    
}


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

推荐阅读更多精彩内容

  • 树的概述 树是一种非常常用的数据结构,树与前面介绍的线性表,栈,队列等线性结构不同,树是一种非线性结构 1.树的定...
    Jack921阅读 4,445评论 1 31
  • 二叉树 满二叉树 国内教程定义:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,...
    简_爱SimpleLove阅读 4,267评论 0 3
  • 数据结构和算法--二叉树的实现 几种二叉树 1、二叉树 和普通的树相比,二叉树有如下特点: 每个结点最多只有两棵子...
    sunhaiyu阅读 6,446评论 0 14
  • 本文转自 http://www.cnblogs.com/manji/p/4903990.html二叉树-****你...
    doublej_yjj阅读 679评论 0 8
  • 1.什么是二叉树? 在计算机科学中,二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”和“右子树”,...
    zcaaron阅读 1,259评论 2 15