堆,堆排序

简介: 堆,堆排序

堆是一棵完全二叉树,如果其父亲结点的值均比孩子结点大,称大顶堆,反之称为小顶堆,学过数据结构知道用数组表示完全二叉树最为简便,自然而然,我们这里也就用数组来表示堆。

如果数组是从序号1开始,对一棵完全二叉树,下列点如果存在,则对结点i/2是父亲结点,2i和2i+1是左右孩子结点。


1.堆


以建大顶堆为例:

建堆过程可以通过比赛规则来模拟,两两对决决出一个强者,强者再对决…最后在最顶上的就是最强者,这样形成的完全二叉树可以保证每一个父亲结点比其下面的孩子结点要强,只要我们保证所有父亲结点满足上述条件就可以了,而在保证每一个父亲结点是不是最大时,自然要和他下面的孩子结点比,这样由上相下比就是一个向下调整的过程,这个过程会重复多次,不妨先建立一个向下调整的函数

void downadjust(int low,int n){   //向下调整操作 ,low为父亲结点,共n个元素
  int p=2*low;
  while(p<=n){                        
    int temp=p;
    if(p<n&&heap[p]<heap[p+1])temp=p+1;        //找出孩子较大个
    if(heap[p/2]<heap[temp])                  //没有它大,调下去
    {
    swap(heap[p/2],heap[temp]);
    p=temp*2;
    }
    else {
    break;}
  } 
}

现在考虑建堆,完全二叉树的父亲结点共n/2个,只要对这些结点向下调整即可,唯一值得思考是从第一个开始还是从最后一个开始,实际上面的那个向下调整函数是默认下面是大根堆的(思考一下为什么),所以自然是从最后一个父亲结点开始。

void createheap(int n) {                               //建立大根堆 
  for(int i=n/2;i>=1;i--)
  downadjust(i,n);
}

建堆完成后考虑一下删除元素和加入元素,删除最大元素的话,只要把最后一个元素发在堆顶,视堆共n-1,个元素进行一次向下调整即可。

那如何加入元素呢?这里我们直接把元素放在最后一位,对比向下调整,我们来一次向上调整即可。

void upadjust(int n) {     //向上调整操作
   int temp=n/2;
   while(temp>=1){
    if(heap[n]>heap[temp]){
      swap(heap[n],heap[temp]);
    n=temp;
    temp=n/2;
     }
    else{break;} 
   }  
}

2.堆排序


堆排序实际是一种选择排序,正是利用了堆,选择效率比简单选择排序快了许多,我们可以利用大根堆每次把最大元素选出来,放在数列末尾,有点类似于堆删除元素,重复n-1次:

void heapsort(int n){
  createheap(n);
  for(int i=n;i>1;i--)
  {
    swap(heap[1],heap[i]);
    downadjust(1,i-1);
  } 
}

最后附完整的编程代码:


#include <iostream>
#include<algorithm>
using namespace std;
const int maxn=101;
int heap[maxn];
void downadjust(int low,int n){                            //向下调整操作 
  int p=2*low;
  while(p<=n){
    int temp=p;
    if(p<n&&heap[p]<heap[p+1])temp=p+1;           //大根 
    if(heap[p/2]<heap[temp])
    {
    swap(heap[p/2],heap[temp]);
    p=temp*2;
    }
    else {
    break;}
  } 
}
void upadjust(int n) {
   int temp=n/2;
   while(temp>=1){
    if(heap[n]>heap[temp]){
      swap(heap[n],heap[temp]);
    n=temp;
    temp=n/2;
     }
    else{break;} 
   }  
}
void createheap(int n) {                               //建立大根堆 
  for(int i=n/2;i>=1;i--)
  downadjust(i,n);
}
void heapsort(int n){
  createheap(n);
  for(int i=n;i>1;i--)
  {
    swap(heap[1],heap[i]);
    downadjust(1,i-1);
  } 
}
int main(){
  heap[1]=6;
  heap[2]=9;
  heap[3]=1;
  heap[4]=5;
  heap[5]=9;
  heapsort(5);
  for(int i=1;i<=5;i++)
  cout<<heap[i]<<" ";
  return 0;
}
相关文章
|
6月前
|
算法
数据结构——堆的应用 堆排序详解
数据结构——堆的应用 堆排序详解
数据结构——堆的应用 堆排序详解
|
2月前
|
前端开发 算法 JavaScript
最小堆最大堆了解吗?一文了解堆在前端中的应用
该文章详细解释了堆数据结构(特别是最小堆)的概念与性质,并提供了使用JavaScript实现最小堆的具体代码示例,包括堆的插入、删除等操作方法。
最小堆最大堆了解吗?一文了解堆在前端中的应用
|
5月前
|
存储 算法
面试必知必会|理解堆和堆排序
面试必知必会|理解堆和堆排序
|
存储 算法
优先级队列(堆)&&  堆排序
优先级队列(堆)&&  堆排序
50 0
|
6月前
|
算法 C语言
堆的应用:堆排序
堆的应用:堆排序
96 0
|
11月前
|
存储 C语言
堆与堆排序操作详解
堆与堆排序操作详解
堆/选择/插入/希尔排序
堆/选择/插入/希尔排序
51 0
|
算法
【数据结构与算法】堆的应用:堆排序和topk问题
【数据结构与算法】堆的应用:堆排序和topk问题
79 0
【树与二叉树】堆的时间复杂度详解以及堆的应用—堆排序、TOP - K问题
【树与二叉树】堆的时间复杂度详解以及堆的应用—堆排序、TOP - K问题