数据结构-选择排序-堆排序
2017-04-11 16:41
369 查看
选择排序
①简单选择排序。
②树形选择排序。
③堆排序。←this
堆排序(Heap Sort)只需要一个记录大小的辅助空间,每个待排序的记录仅占有一个存储空间。
堆定义:满足ki<=k2;且ki<=k(2i+1) (i=1,2,...,n/2)完全二叉树且父比子大(或父比子小)
堆排序方法对记录较少的文件不值得提倡,对n较大的文件还是很有效的。因为其运行时间主要耗费在建初始堆,和调整新堆
最大优点是,堆排序的最坏情况下,时间复杂度也是O(nlogn)。
首先介绍堆运算:
①
Sift-Up
简单来说就是二叉树的结点(样例用叶子)突然变大,需要重新对堆进行排列。从下往上传递(交换)更大的值
20 20 25
/ \ / \ / \
17 9 5变成25 17 9 25向上
20 9
/ \ / \ ----------> / \ / \ ----------> / \
/ \
10 11 4 5 10 11 4 5 10 17
4 5
/ \ / / \ / / \ /
3 7 5 3 7 25
3 7 11
输入:数组H[ 1...n ] 和位于1和n之间的索引 i
输出:上移H[ i ](如果需要),使他不大于父节点。
②Sift-Down
简单来说就是二叉树的某根突然变小,需要重新对堆进行排列,从上往下传递(交换)更小的值
20 20 20
/ \ / \ / \
17 9 17变成3 3 9 3往下
11 9
/ \ / \ ----------> / \ / \ ----------> / \ / \
10 11 4 5 10 11 4 5 10 5 4 5
/ \ / / \ / / \ /
3 7 5 3 7 5 3 7 3
输入:数组H[ 1...n ] 和位于1和n之
4000
间的索引i
输出:下移H[ i ](如果需要),以使它不小于子节点。
③插入数值
在树的最后添上一个数,然后执行Sift-Up,从下到上重新排列一下,保持堆的特性
20 20 20
/ \ / \ / \
17 9 插入18 17 9 Sift-Up 18
9
/ \ / \ ----------> / \ / \ ----------> / \ / \
10 11 4 5 10 11 4 5 10 17 4 5
/ \ / / \ / \ / \ / \
3 7 5 3 7 5 18 3 7
5 11
输入:数组H[ 1...n ] 和元素x。
输出:新的堆H[ 1...n+1 ],x为其元素之一。
④
删除数值
从堆里删除元素,先将最后一个叶子跟要删除的数值交换,
如果最后一个叶子比较大那么Sift-Up,从下到上重新排列一下
如果最后一个叶子比较小那么Sift-Down,从上到下重新排列一下
20 20 20 20
/ \ 要删除10 / \ / \
/ \
17 9 10和5交换 17 9 删除10 17 9
Sift-Down 17 9
/ \ / \ ----------> / \ / \ ----------> / \ / \ ----------> / \
/ \
10 11 4 5 5 11 4 5
5 11 4 5 7 11
4 5
/ \ / / \ / / \ / \
3 7 5 3 7 10
3 7 3 5
输入:非空堆H[ 1...n ] 和位于1和n之间的索引i
输出:删除H[ i ]之后的新堆H[ 1...n-1]
⑤创建堆
从叶子的上一个根到整个的根节点,每一次都将小的数沉下来
★sift-down是根向叶子的调整,从叶子开始毫无意义,所以直接跳过叶子部分
⑥堆排序
因为每次堆顶端都是最大值,那么,把最后的那个换成堆顶端,那么最大值就在最后面了。
依次把当前最大值放到后面,那么就可以排出从小到大的顺序了。
所要用到的步骤是:⑤创建堆+②Sift-Down
20 5
17
/ \ / \ 无视20 / \
17 9 20交换5
17 9 从顶sift-down
11 9
17交换7
/ \ / \ ----------> / \ / \ ----------> / \ / \
----------> ...省略...
10 11 4 5 10 11 4 5 10 5
4 5
/ \ / / \ / / \ /
3 7 5
3 7 20 3 7
20
那么问题来了?从大到小排序怎么弄呢?
把sift_down()里的第七行和第九行改一下方向就行了,每次堆顶都是最小值->最小堆
堆排序到此结束。
①简单选择排序。
②树形选择排序。
③堆排序。←this
堆排序(Heap Sort)只需要一个记录大小的辅助空间,每个待排序的记录仅占有一个存储空间。
堆定义:满足ki<=k2;且ki<=k(2i+1) (i=1,2,...,n/2)完全二叉树且父比子大(或父比子小)
堆排序方法对记录较少的文件不值得提倡,对n较大的文件还是很有效的。因为其运行时间主要耗费在建初始堆,和调整新堆
最大优点是,堆排序的最坏情况下,时间复杂度也是O(nlogn)。
首先介绍堆运算:
①
Sift-Up
简单来说就是二叉树的结点(样例用叶子)突然变大,需要重新对堆进行排列。从下往上传递(交换)更大的值
20 20 25
/ \ / \ / \
17 9 5变成25 17 9 25向上
20 9
/ \ / \ ----------> / \ / \ ----------> / \
/ \
10 11 4 5 10 11 4 5 10 17
4 5
/ \ / / \ / / \ /
3 7 5 3 7 25
3 7 11
输入:数组H[ 1...n ] 和位于1和n之间的索引 i
输出:上移H[ i ](如果需要),使他不大于父节点。
// 堆a,根i void sift_up(int *a,int i){ bool done=false; if(i==1) return ; //总根 while(i!=1 && !done){ if( a[i] > a[i/2] ) //子比父大,换 swap(a[i],a[i/2]); else done = true; i=i/2; } }
②Sift-Down
简单来说就是二叉树的某根突然变小,需要重新对堆进行排列,从上往下传递(交换)更小的值
20 20 20
/ \ / \ / \
17 9 17变成3 3 9 3往下
11 9
/ \ / \ ----------> / \ / \ ----------> / \ / \
10 11 4 5 10 11 4 5 10 5 4 5
/ \ / / \ / / \ /
3 7 5 3 7 5 3 7 3
输入:数组H[ 1...n ] 和位于1和n之
4000
间的索引i
输出:下移H[ i ](如果需要),以使它不小于子节点。
// 堆a,子根i ,总n void sift_down(int *a,int i,int n){ bool done=false; if(2*i > n) return ; //根i是叶子 while(2*i<=n && !done){ i=2*i; //根i叶子 if(i+1<=n && a[i+1]>a[i]) //根i两个叶子里选个大的 i=i+1; if(a[i/2] < a[i]) // 父比子大,换 swap(a[i],a[i/2]); else done = true; } }
③插入数值
在树的最后添上一个数,然后执行Sift-Up,从下到上重新排列一下,保持堆的特性
20 20 20
/ \ / \ / \
17 9 插入18 17 9 Sift-Up 18
9
/ \ / \ ----------> / \ / \ ----------> / \ / \
10 11 4 5 10 11 4 5 10 17 4 5
/ \ / / \ / \ / \ / \
3 7 5 3 7 5 18 3 7
5 11
输入:数组H[ 1...n ] 和元素x。
输出:新的堆H[ 1...n+1 ],x为其元素之一。
// 堆a,数x,总n void insert(int *a,int x,int &n){ n=n+1; a =x; sift_up(a,n); }
④
删除数值
从堆里删除元素,先将最后一个叶子跟要删除的数值交换,
如果最后一个叶子比较大那么Sift-Up,从下到上重新排列一下
如果最后一个叶子比较小那么Sift-Down,从上到下重新排列一下
20 20 20 20
/ \ 要删除10 / \ / \
/ \
17 9 10和5交换 17 9 删除10 17 9
Sift-Down 17 9
/ \ / \ ----------> / \ / \ ----------> / \ / \ ----------> / \
/ \
10 11 4 5 5 11 4 5
5 11 4 5 7 11
4 5
/ \ / / \ / / \ / \
3 7 5 3 7 10
3 7 3 5
输入:非空堆H[ 1...n ] 和位于1和n之间的索引i
输出:删除H[ i ]之后的新堆H[ 1...n-1]
// 堆a,下标i,总n void delet(int *a,int i,int &n){ int x=a[i],y=a ;a =0; n=n-1; if(i == n+1) //删的是最后一个点,那已经删掉了 return ; a[i]=y; //用最后一个叶子覆盖这个结点 if(y>=x) sift_up(a,i); //换上的比原来大,上浮 else sift_down(a,i,n); //小,下沉 }
⑤创建堆
从叶子的上一个根到整个的根节点,每一次都将小的数沉下来
★sift-down是根向叶子的调整,从叶子开始毫无意义,所以直接跳过叶子部分
// 数组a,长度n void build(int *a,int n){ for(int i=n/2;i>=1;i--){ //从一半开始到根节点 sift_down(a,i,n); } }
⑥堆排序
因为每次堆顶端都是最大值,那么,把最后的那个换成堆顶端,那么最大值就在最后面了。
依次把当前最大值放到后面,那么就可以排出从小到大的顺序了。
所要用到的步骤是:⑤创建堆+②Sift-Down
20 5
17
/ \ / \ 无视20 / \
17 9 20交换5
17 9 从顶sift-down
11 9
17交换7
/ \ / \ ----------> / \ / \ ----------> / \ / \
----------> ...省略...
10 11 4 5 10 11 4 5 10 5
4 5
/ \ / / \ / / \ /
3 7 5
3 7 20 3 7
20
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N=30;
void print(int *tree){
int altm=0;
for(int j=1;j<5;j++){
int tm=1;
for(int i=1;i<j;i++)
tm*=2;
for(int i=1;i<=tm;++i)
{
printf("%d ",tree[altm+i]);
}
printf("\n");altm+=tm;
}
}
// 堆a,子根i ,总n
void sift_down(int *a,int
d18f
i,int n){
bool done=false;
if(2*i > n) return ; //根i是叶子
while(2*i<=n && !done){
i=2*i; //根i叶子
if(i+1<=n && a[i+1]>a[i]) //根i两个叶子里选个大的
i=i+1;
if(a[i/2] < a[i]) // 父比子大,换
swap(a[i],a[i/2]);
else done = true;
}
}
// 数组a,长度n void build(int *a,int n){ for(int i=n/2;i>=1;i--){ //从一半开始到根节点 sift_down(a,i,n); } }
void heapSort(int *a,int n){
build(a,n);
for(int j=n;j>=2;j--){
swap(a[1],a[j]);
sift_down(a,1,j-1);
}
}
int main()
{
int a
={0,3,7,5,10,5,4,9,20,17,11};
int len=10;
print(a);
//build(a,len);print(a);printf("---%d\n",len);
//insert(a,13,len);print(a);printf("---%d\n",len);
//delet(a,5,len);print(a); printf("---%d\n",len);
heapSort(a,len);
print(a);
for(int i=1;i<=len;i++){
printf("%d ",a[i]);
}printf("\n");
return 0;
}
那么问题来了?从大到小排序怎么弄呢?
把sift_down()里的第七行和第九行改一下方向就行了,每次堆顶都是最小值->最小堆
堆排序到此结束。
相关文章推荐
- 【数据结构】排序番外篇 堆,堆排序与其前身选择排序
- 数据结构 JAVA描述(十一) 选择排序(直接选择排序,树形选择排序,堆排序)
- 数据结构学习笔记5-寻找最小的k个数(选择排序和堆排序)
- 数据结构和算法分析之排序算法--选择排序(堆排序)
- 数据结构:排序算法之堆排序和选择排序
- c++实现数据结构中的各种排序方法:直接插入、选择,归并、冒泡、快速、堆排序、shell排序
- 数据结构学习笔记 --- 排序(选择排序、堆排序)
- C++代码,数据结构-内部排序-选择排序-堆排序
- 图解"数据结构--内部排序算法"----选择排序:直接选择排序、堆排序
- 【数据结构】常用比较排序算法(包括:选择排序,堆排序,冒泡排序,选择排序,快速排序,归并排序)
- 数据结构例程——选择排序之堆排序
- java数据结构之插入排序(选择排序(直接选择排序、堆排序))
- 我---对‘数据结构’中‘排序’的理解 ---------3:选择排序--(二)堆排序
- 【数据结构】常用比较排序算法(包括:选择排序,堆排序,冒泡排序,选择排序,快速排序,归并排序)
- 数据结构&算法实践—【排序|选择排序】堆排序
- 【数据结构和算法】排序算法之二:选择排序和堆排序
- 数据结构学习笔记 --- 排序(选择排序、堆排序)
- 【数据结构和算法】排序算法之二:选择排序和堆排序
- 堆排序--数据结构排序1