堆和堆排序

堆的概念

  1. 树的形状:要求为完全二叉树(树的每一层都是满的除了最后一层最右边的元素可以缺位)
  2. 父母优势(堆特性):每一个节点的键都要大于或者等于它子女的键
    将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆
    大堆:完全二叉树中发现:每个节点都比其孩子节点大
    小堆:完全二叉树中发现:每个节点都比其孩子节点小

堆的概念

堆的特性

  1. 只存在一颗n个节点的完全二叉树。高度为[log2N](向下取整)+1
  2. 堆的根包含了堆的最大元素
  3. 堆的一个节点以及该节点的子孙也是一个堆
  4. 可以用数组来实现堆,方法是用从上到下,从左到右的方式记录堆元素,在数组的1~n的位置上存放堆元素,留下H[0],让它空着或者放一个限位器,它的值大于堆中的任何一个元素,在这种表示法中:
    a.父母结点的键位于前[n/2](向下取整)个位置中,而叶子结点的键会占据后[n/2](向上取整)个元素中
    b.数组中,某个位于父母i的键的子女会在2i和2i+1。相应的对于一个位于i的键来说,它的父母将在[n/2](向下取整)

堆的构造

  1. 自底向上堆构造
  2. 自顶向下堆构造

堆的插入和删除

堆排序

  1. 第一步:构造堆,即为一个给定的数组构造一个堆
  2. 第二步:删除最大键,即对剩下的堆应用n-1次根删除操作

堆排序代码实现

#include <queue>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
#define MAX 1010

using namespace std;

int S[MAX];

/*!!堆排序(S从0开始存储)!!*/

void PerDown(int p, int N)//P为父节点的位置 
{
    int Parent, Child;
    int X = S[p];//X为父节点值 
    //左儿子小于N时执行,数组从0开始
    for(Parent = p; Parent*2+1 < N; Parent = Child)//循环的目的是如果一个父节点小于子节点,和子节点换位后,需要继续和新的孩子节点比较 
    {
        Child = Parent*2+1;//注意S从0开始储存,所以这里的Child为Parent的左孩子 
        if(Child != N - 1 && S[Child] < S[Child + 1])
            Child++;//比较左右孩子,Child指向左右孩子中较大的 
        if(X >= S[Child]) break;//如果父节点的值大于左右孩子中较大的值,则退出循环 
        else S[Parent] = S[Child];//否则换位 
    }
    S[Parent] = X;
}

void HeapSort(int N)
{
    //将S调整为最大堆
    for(int i = N/2 - 1; i >= 0; i--)//遍历父母结点 
        PerDown(i, N);
    for(int i = N - 1; i >0; i--)
    {
        //将最大值换到最后
        swap(S[0], S[i]);
        //重新调整剩下的为最大堆,最后一个已排好忽略后面的
        PerDown(0, i);
    }
}

void Print(int N)
{
    for(int i = 0; i < N; i++) cout<< S[i] <<" ";
}

int main()
{
    int N ;
    cout<<"Please enter the number of the numbers:"; 
    cin>>N;
	cout<<"Please enter the numbers :"; 
    for(int i = 0; i < N; i++) cin >> S[i];
    HeapSort(N);//进行堆排序 
    Print(N);//输出 
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值