看了左神的堆排序,觉得思路很清晰,比常见的递归的堆排序要更容易理解,所以自己整理了一下笔记,带大家一步步实现堆排序算法

首先介绍什么是大根堆:每一个子树的最大值都是子树的头结点,即根结点是所有结点的最大值

堆排序是基于数组和二叉树思想实现的(二叉树是脑补结构,实际是数组)

堆排序过程

1、数组建成大根堆,首先,遍历所有结点,当前结点index和父结点(index-1)/ 2 比较 (当前数组的下标是index,此结点的父结点的下标就是(index-1)/ 2  ),如果比父结点大,交换,变成父结点的位置再和上一层的父结点比较,直到满足大根堆条件

int swap(int source[], int a, int b)
{
int temp = source[a];
source[a] = source[b];
source[b] = temp;
}
int heapsort(int source[], int len)
{
for (int i = ; i <len; i++)
{
heapInsert(source, i);
}
}
int heapInsert(int source[], int index)
{
while (source[index] > source[(index - ) / ])
{
swap(source, index, (index - ) / );
index = (index - ) / ;
}
}

2、让根结点和最后一个结点交换位置,也就是数组的第一个数和最后一个数交换位置,接下来最后一个数不用考虑了,比如一个数组有5个数,定义一个变量size=5,大根堆的根结点放到最后一个数后,--size

int size = len;
swap(source, , --size);

3、让交换后的头结点经历一个向下的调整,让结点和自己的两个孩子比较,如果孩子的值比头结点大,交换,交换到孩子结点位置,继续和下面的两个孩子比较,直到满足大根堆条件

int heapify(int source[], int index, int size)//index表示要和它两个孩子比较的结点
{
int left = index * + ; //找到index左孩子结点的数组下标
while (left < size)
{
int largest = left + < size && source[left + ] > source[left] ? source[left + ] : source[left];//如果有右孩子且右孩子比左孩子大,令largest=右孩子的值,也就是把两个孩子中最大的一个数赋给largest
if (source[index] < source[largest])
{
swap(source, index, largest);
index = largest;
left = index * + ;
}
else break;
} }

4、重复第2步,第3步,直到size = 0 ,整个数组排序过程结束

while (size > )
{
swap(source, , --size);
heapify(source, , size);
}

源代码如下

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int swap(int source[], int a, int b)
{
int temp = source[a];
source[a] = source[b];
source[b] = temp;
}
int heapsort(int source[], int len)
{
for (int i = ; i < len; i++)
{
heapInsert(source, i);
}
int size = len;
while (size > )
{
swap(source, , --size);
heapify(source, , size);
}
}
int heapInsert(int source[], int index)
{
while (source[index] > source[(index - ) / ])
{
swap(source, index, (index - ) / );
index = (index - ) / ;
}
}
int heapify(int source[], int index, int size)//index表示要和它两个孩子比较的结点
{
int left = index * + ; //找到index左孩子结点的数组下标
while (left < size)
{
int largest = left + < size && source[left + ] > source[left] ? left + : left;//如果有右孩子且右孩子比左孩子大,令largest=右孩子的值,也就是把两个孩子中最大的一个数赋给largest
if (source[index] < source[largest])
{
swap(source, index, largest);
index = largest;
left = index * + ;
}
else break;
} }
int main()
{
int source[] = { ,,,,,,,,,,,,,,,,, };
int len;
len = sizeof(source) / sizeof(int);
heapsort(source, len);
for (int i = ; i < len; i++)
{
printf("%d ", source[i]);
} }

输出结果

以上就是堆排序的所有细节,这个版本很优良,堆排序的额外空间复杂度是O(1),如果用递归的话,递归有递归栈,额外空间复杂度不就上去了吗,设计成这种迭代的可以省空间,时间复杂度为O(n log n)

转载请注明出处、作者  谢谢

算法-一步步教你如何用c语言实现堆排序(非递归)的更多相关文章

  1. 自己写算法---java的堆的非递归遍历

    import java.io.*; import java.util.*; public class Main { public static void main(String args[]) { S ...

  2. 一步步教你轻松学奇异值分解SVD降维算法

    一步步教你轻松学奇异值分解SVD降维算法 (白宁超 2018年10月24日09:04:56 ) 摘要:奇异值分解(singular value decomposition)是线性代数中一种重要的矩阵分 ...

  3. 一步步教你轻松学支持向量机SVM算法之案例篇2

    一步步教你轻松学支持向量机SVM算法之案例篇2 (白宁超 2018年10月22日10:09:07) 摘要:支持向量机即SVM(Support Vector Machine) ,是一种监督学习算法,属于 ...

  4. 一步步教你轻松学支持向量机SVM算法之理论篇1

    一步步教你轻松学支持向量机SVM算法之理论篇1 (白宁超 2018年10月22日10:03:35) 摘要:支持向量机即SVM(Support Vector Machine) ,是一种监督学习算法,属于 ...

  5. 一步步教你轻松学主成分分析PCA降维算法

    一步步教你轻松学主成分分析PCA降维算法 (白宁超 2018年10月22日10:14:18) 摘要:主成分分析(英语:Principal components analysis,PCA)是一种分析.简 ...

  6. 一步步教你轻松学关联规则Apriori算法

    一步步教你轻松学关联规则Apriori算法 (白宁超 2018年10月22日09:51:05) 摘要:先验算法(Apriori Algorithm)是关联规则学习的经典算法之一,常常应用在商业等诸多领 ...

  7. 一步步教你轻松学K-means聚类算法

    一步步教你轻松学K-means聚类算法(白宁超  2018年9月13日09:10:33) 导读:k-均值算法(英文:k-means clustering),属于比较常用的算法之一,文本首先介绍聚类的理 ...

  8. 一步步教你轻松学朴素贝叶斯模型算法Sklearn深度篇3

    一步步教你轻松学朴素贝叶斯深度篇3(白宁超   2018年9月4日14:18:14) 导读:朴素贝叶斯模型是机器学习常用的模型算法之一,其在文本分类方面简单易行,且取得不错的分类效果.所以很受欢迎,对 ...

  9. 一步步教你轻松学KNN模型算法

    一步步教你轻松学KNN模型算法( 白宁超 2018年7月24日08:52:16 ) 导读:机器学习算法中KNN属于比较简单的典型算法,既可以做聚类又可以做分类使用.本文通过一个模拟的实际案例进行讲解. ...

随机推荐

  1. SilverlightMVVM模式中的数据校验

    silverlight的数据校验大体分成3种类型: 数据是非必填的但是需要满足相应数据格式的 数据是必填的且可能需要进行数据格式校验的 其他(如数据的联动校验) 以下的数据校验方式针对第二种: 在相应 ...

  2. 分享Node.js + Koa2 + MySQL + Vue.js 实战开发一套完整个人博客项目网站

    这是个什么的项目? 使用 Node.js + Koa2 + MySQL + Vue.js 实战开发一套完整个人博客项目网站. 博客线上地址:www.boblog.com Github地址:https: ...

  3. 上不了名校?可以在 GitHub 上读他们的课程

    今天开始,全国各大区域的高考成绩陆续公布,又到了几家欢喜几家愁的时刻,如果你准备报考计算机相关专业,但是又由于分数不高而苦恼.别担心,在 GitHub 上有着大量的名校教学资源,即使上不了名校,也可以 ...

  4. 【JDK】ArrayList集合 源码阅读

    这是博主第二次读ArrayList 源码,第一次是在很久之前了,当时读起来有些费劲,记得那时候HashMap的源码还是哈希表+链表的数据结构. 时隔多年,再次阅读起来ArrayList感觉还蛮简单的, ...

  5. jQuery入门——注册事件

    下面举例介绍注册事件的几种方法: 以光棒效果为例 1.bind注册: <!DOCTYPE html> <html> <head> <meta charset= ...

  6. Spring5深度源码分析(三)之AnnotationConfigApplicationContext启动原理分析

    代码地址:https://github.com/showkawa/spring-annotation/tree/master/src/main/java/com/brian AnnotationCon ...

  7. 深度探索c++对象模型 第一章

    1,声明与定义. //声明式如下: extern int x;   //对象式(变量式)声明 std::size_t numDigits(int number);  //函数式声明 class Wid ...

  8. 生产力工具:shell 与 Bash 脚本

    生产力工具:shell 与 Bash 脚本 作者:吴甜甜 个人博客网站: wutiantian.github.io 注意:本文只是我个人总结的学习笔记,不适合0基础人士观看. 参考内容: 王顶老师 l ...

  9. ZOJ 3962:Seven Segment Display(思维)

    https://vjudge.net/problem/ZOJ-3962 题意:有16种灯,每种灯的花费是灯管数目,代表0~F(十六进制),现在从x开始跳n-1秒,每一秒需要的花费是表示当前的数的花费之 ...

  10. kuangbin专题 专题一 简单搜索 Fire Game FZU - 2150

    题目链接:https://vjudge.net/problem/FZU-2150 题意:’ . '代表火无法烧着的地方,‘ # ’表示草,火可以烧着.选择任意两个‘ # ’(可以两个都选同一个 ‘ # ...