最近在自学算法导论,看到堆排序这一章,来做一下笔记。
堆排序是一种时间复杂度为O(lgn)的原址排序算法。它使用了一种叫做堆的数据结构。
堆排序具有空间原址性,即指任何时候都需要常数个额外的元素空间存储临时数据。

堆:
二叉堆是一个数组,它可以被看成一个近似的完全二叉树。
除了最底层以外,该树是满的;且最底层是从左向右填充。
堆又可以分为大根堆和小根堆。
大根堆:爸爸元素值>=儿子元素值
小根堆:爸爸元素值<=儿子元素值
可以把堆看成是一棵树,把堆的高度定义为根结点的高度。

建立一个堆包含建立堆(build_max_heap)和维护堆(max_heapify)两个操作。

维护堆(max_heapify):
由于大根堆具有根节点元素大于或等于孩子元素的特点。在输出堆顶或者堆排序的过程中,可能存在着大根堆“大根”性质被破坏的情况。这是就需要使用维护堆对大根堆进行“大根”性质的维护。
调用此函数传入一个数组arr与要调节位置的元素i 要求元素i的左右孩子都是大根堆
此时就可以用max_heapify通过让数组arr[i]的值在大根堆中逐步下降,使得下标为i的根结点所在的子树重新遵循大根堆的性质。
算法思想:
在(max_heapify)算法执行的过程中,每次从arr[i]、arr[left]、和arr[right]中选择一个最大的元素,将下标保存在largest中。并将arr[largest]与arr[i]的元素值进行交换。
若当前arr[i]为最大的元素,则程序结束。(由调用(max_heapify)的前提可以知道除了当前结点i以外,其左右子树必然符合大根堆的性质。)否则则递归调用(max_heapify(arr,largest,heap_size)继续对堆进行调整。
算法如下:

void max_heapify(int arr[],int i,int heap_size)//i为当前元素节点
{
int largest;
int left=*i;
int right=*i+;
if(left<=heap_size&&arr[left]>arr[i]) largest=left;
else largest=i;
if(right<=heap_size&&arr[right]>arr[largest])
largest=right;
if(largest!=i)
{
swap(arr[largest],arr[i]);
max_heapify(arr,largest,heap_size);
}
}

建立堆(build_max_heap):
在一个数组上建立堆可以自底向上地利用(max_heapify)来逐步调整数组,使其最后建成大根堆。
这里值得一提的是为什么要从n/2到1这样的顺序进行建堆。
从堆的性质我们可以知道,下标(n/2...n)的元素必然是叶子元素,而单个叶子元素也符合大根堆的性质。调用(max_heapify)的前提是当前i元素的子树得全是大根堆。所以建堆只能从下往上建。

void build_max_heap(int arr[],int length)
{
int heap_size=length;
for(int i=length/; i>=; i--)
{
max_heapify(arr,i,heap_size);
}
}

堆排序(heapsort):
堆排序是在堆的基础上进行的。
将大根堆进行排序,使数组升序排列的堆排序算法思想如下:
首先把根顶arr[1]与最后一个元素arr[n]进行交换,这样最大的元素便换到了最底
交换后heap_size减1
对余下的部分,由于交换了元素大根堆的性质遭到破坏。这时调用(max_heapify(arr,1,heap_size))对堆进行调整,使得最大的元素在最上
然后又交换根顶和最后一个元素(此时已是arr[1]与arr[n-1]),
heap_size减1,重复调用(max_heapify)来调整堆的性质……
就这样对下标为第n-1到2的元素进行调整。
最后即可将数组使数组呈升序排列。
具体算法如下:

void heapsort(int arr[],int length)
{
int heap_size=length;
build_max_heap(arr,length);
for(int i=length; i>=; i--)
{
swap(arr[],arr[i]);
heap_size--;
max_heapify(arr,,heap_size);
}
}

总代码如下:

#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
void max_heapify(int arr[],int i,int heap_size)//i为当前元素节点
{
int largest;
int left=*i;
int right=*i+;
if(left<=heap_size&&arr[left]>arr[i]) largest=left;
else largest=i;
if(right<=heap_size&&arr[right]>arr[largest])
largest=right;
if(largest!=i)
{
swap(arr[largest],arr[i]);
max_heapify(arr,largest,heap_size);
}
}
void build_max_heap(int arr[],int length)
{
int heap_size=length;
for(int i=length/; i>=; i--)
{
max_heapify(arr,i,heap_size);
}
}
void heapsort(int arr[],int length)
{
int heap_size=length;
build_max_heap(arr,length);
for(int i=length; i>=; i--)
{
swap(arr[],arr[i]);
heap_size--;
max_heapify(arr,,heap_size);
}
}
int main()
{
int arr[]= {,,,,,,,,,,};
int len=;
heapsort(arr,len);
cout<<"heapsort:\n";
for(int i=; i<=len; i++)
{
cout<<arr[i]<<' ';
}
cout<<endl;
return ;
}

堆与堆排序/Heap&Heap sort的更多相关文章

  1. 堆排序(Heap Sort)的C语言实现

    堆排序(Heap Sort)具体步骤为 将无序序列建成大顶堆(小顶堆):从最后一个非叶子节点开始通过堆调整HeapAdjust()变成小顶堆或大顶堆 将顶部元素与堆尾数组交换,此是末尾元素就是最大值, ...

  2. 【算法】堆排序(Heap Sort)(七)

    堆排序(Heap Sort) 堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法.堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父 ...

  3. Java实现的二叉堆以及堆排序详解

    一.前言 二叉堆是一个特殊的堆,其本质是一棵完全二叉树,可用数组来存储数据,如果根节点在数组的下标位置为1,那么当前节点n的左子节点为2n,有子节点在数组中的下标位置为2n+1.二叉堆类型分为最大堆( ...

  4. 基本数据结构 —— 堆以及堆排序(C++实现)

    目录 什么是堆 堆的存储 堆的操作 结构体定义 判断是否为空 往堆中插入元素 从堆中删除元素 取出堆中最大的元素 堆排序 测试代码 例题 参考资料 什么是堆 堆(英语:heap)是计算机科学中一类特殊 ...

  5. PHP面试:说下什么是堆和堆排序?

    堆是什么? 堆是基于树抽象数据类型的一种特殊的数据结构,用于许多算法和数据结构中.一个常见的例子就是优先队列,还有排序算法之一的堆排序.这篇文章我们将讨论堆的属性.不同类型的堆以及堆的常见操作.另外我 ...

  6. python下实现二叉堆以及堆排序

    python下实现二叉堆以及堆排序 堆是一种特殊的树形结构, 堆中的数据存储满足一定的堆序.堆排序是一种选择排序, 其算法复杂度, 时间复杂度相对于其他的排序算法都有很大的优势. 堆分为大头堆和小头堆 ...

  7. [MIT6.006] 4. Heaps and Heap Sort 堆,堆排序

    第4节课仍然是讲排序,但介绍的是一种很高效的堆排序. 在编程过程中,有时候会需要进行extrat_max的操作,即从一个数列里挨个抽取最大值并将其它从原数列中移除.而排序问题也可以看作是一个extra ...

  8. 算法:堆排序(Heap Sort)

    备注 考虑到 Heap 的特性,很容易想到将其用作排序的用处,为了提高效率需要适当的改进一下,如:in place remove 和 in place move down. 代码 using Syst ...

  9. 选择排序(2)——堆排序(heap sort)

    前期概念: 二叉树 完全二叉树 左序遍历 中序遍历 右序遍历 堆 小根堆 大根堆 堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种.可以利用数组的特点 ...

随机推荐

  1. Ethernet II和802.3

    在卷一中:(章节二:数据链路层) 在T C P / I P协议族中,链路层主要有三个目的: (1)为IP模块发送和接收IP数据报: (2 )为ARP模块发送ARP请求和接收ARP应答: (3 )为RA ...

  2. 2.2.2synchronized同步代码块的使用

    当两个并发线程访问同一个对象object中的synchronized(this)同步代码块时,一段时间内只能有一个线程执行,另一个线程必须等待期执行完才能执行. package com.cky.bea ...

  3. 改Android手机定位位置

    手机定位方法 1,gps等卫星定位,如美国的gps,欧洲的伽利略,中国的北斗等,通过至少三颗卫星,用三角定位和时间等算法,计算出设备的经纬度,到地图上找到这个经纬度的地名 2,移动运营商基站定位,通过 ...

  4. C#-VS异常处理

    VS异常处理 常规 try     可能会产生异常的代码,当一行产生异常,这行下面的代码不执行,转到catch开始执行 catch(system.Exception e)      e.message ...

  5. springMVC一个Controller处理所有用户请求的并发问题

    有状态和无状态的对象基本概念: 有状态对象(Stateful Bean),就是有实例变量的对象 ,可以保存数据,是非线程安全的.一般是prototype scope. 无状态对象(Stateless ...

  6. ceph osd 批量删除

    ceph osd 批量删除,注意删除的是当前节点正在使用的osd,数据删除有风险,所以最后一步没有去format磁盘,给你留下一剂后悔药. #!/bin/bash osd_list=`mount|gr ...

  7. sentiwordnet的简单使用

    # Example line: # POS     ID     PosS  NegS SynsetTerm#sentimentscore    Desc # a   00009618  0.5    ...

  8. poj2828 线段树单点更新

    Buy Tickets Time Limit: 4000 MS Memory Limit: 65536 KB 64-bit integer IO format: %I64d , %I64u Java ...

  9. 在linux上搭建nexus私服(CentOS7)

    1.下载nexus安装包,下载地址 https://www.sonatype.com/download-oss-sonatype?hsCtaTracking=920dd7b5-7ef3-47fe-96 ...

  10. 加密算法(DES,AES,RSA,MD5,SHA1,Base64)比较和项目应用(转载)

    加密技术通常分为两大类:"对称式"和"非对称式". 对称性加密算法:对称式加密就是加密和解密使用同一个密钥.信息接收双方都需事先知道密匙和加解密算法且其密匙是相 ...