优先队列 之 堆排序实现(堆排序思想)

/* 

 1、接上一篇文章,优先队列 之 插入排序 这里是用到了堆排序的思想,而非完全的堆排序的步骤;正如二分思想,他是一种思想,不要
    停留在一种方法上、一种数据结构上。

  2、poj 2833,因为优先队列是由最小(大)堆实现的,时间复杂度O(n*logn)----正好服务优先队列的要求,保证队首(栈顶)
元素的优先级最高,其他元素的优先级顺序不考虑。

  3、数据结构和算法的完美结合,第一次尝试到了两者合力是如此的完美,正如优先队列用到了:

(1):元素出队列,相当于栈顶和最后一个元素交换后,向下调整的过程;(2):元素入队列,相当于向队尾增加一个元素,向上调整的过程。

  4、下面并未体现出优先级的顺序,而是用数字的大校表示优先级,当然可以建立一个结构体struct { weight     key },再加上一个template<class T>写成模板类

*/

#include <iostream>
using namespace std;
const int maxn = 100;
void my_swap(int &a, int &b)
{
    int tmp;
    tmp = a;
    a = b;
    b = tmp;
}
//void heap_sort(int arr[],const int &len);
void heap_sort(int arr[],int &len);
void heap_down_adjust(int arr[],int i,int &len);
void heap_up_adjust(int arr[],int &len);
void heap_init(int arr[],int &len);
bool de_heap_queue(int arr[],int &len);
void en_heap_queue(int arr[],int &len,const int &key);
int main()
{
    int i,len,t_len;// 数组的有效长度
    int arr[maxn],tmp;
    len = 0;
    cout << "请输入一个序列(-1结束):" << endl;
    while(cin >> tmp)
    {
        if(tmp == -1)
            break;
        arr[len] = tmp;
        len++;
    }
    t_len = len;
    heap_init(arr,len);//调用建立初始堆
    cout << "插入一个元素:" << endl;
    cin >> tmp;
    en_heap_queue(arr,len,tmp);
    cout << "按队列的优先顺序出队:" << endl;
    do
    {
        cout << "堆顶元素:" << arr[0] << " " << len << endl;
    }while(de_heap_queue(arr,len));

    return 0;
}

// 堆排序
void heap_sort(int arr[],int &len)
{
    int i;
    for(i=len/2-1; i>=0; --i)// 至于为什么是从i = len/2 -1开始,自己建立一个完全二叉树的数组即可发现规律。
    {
        heap_down_adjust(arr,i,len);
    }// 建立一个初试堆
    //以0 和 len-1为下标的元素交换,之后从0下标开始调整堆,直到剩下一个元素
    for(i=len-1; i>0; --i)
    {
        my_swap(arr[0],arr[i]);
        heap_down_adjust(arr,0,i);// i 代表当前的数组长度
    }

}
// 建立一个初始堆
void heap_init(int arr[],int &len)
{
    int i;
    for(i=len/2-1; i>=0; --i)// 至于为什么是从i = len/2 -1开始,自己建立一个完全二叉树的数组即可发现规律,len是数组长度。
    {
        heap_down_adjust(arr,i,len);
    }// 建立一个初试堆(大顶堆)
}
// 数组,调整位置,数组长度
void heap_down_adjust(int arr[],int i,int &len)
{
    int lc;// 左孩子
    for(; i*2+1<len; i=lc)
    {
        lc = i*2+1;// 从左孩子开始
        if(lc+1<len && arr[lc+1]>arr[lc])//如果右侧孩子大,加一
            lc++;
        if(arr[lc]>arr[i])//较大的孩子节点大于父节点
            my_swap(arr[lc],arr[i]);
        else
            break;//父节点是最大的无需向下调整
    }
}
// 数组,调整位置,数组长度,插入新元素,向上调整;比向下调整简单,
//因为他需要判断左右孩子的最大值与最后一个值(因为是最后一个元素和零号元素交换的)
void heap_up_adjust(int arr[],int i,int &len)
{
    int parent;
    for(i=len-1;i>0;i=parent)
    {
        parent = (i-1)/2;
        if(arr[i]>arr[parent])
            my_swap(arr[i],arr[parent]);
        else// 无需再向上调整
            break;
    }
}
// 删除优先队列的队首元素
bool de_heap_queue(int arr[],int &len)
{
    if(len<=1)
        return false;
    len--;// 相当于删除了,数组从0开始,所以Len-1才是最后一个元素
    my_swap(arr[0],arr[len]);
    heap_down_adjust(arr,0,len);
    return true;
}
//插入队尾元素
void en_heap_queue(int arr[],int &len,const int &key)
{
    arr[len] = key;
    len++;
    heap_up_adjust(arr,len,len);
}

改进之后的swap()函数,异或的好处,以及 位移 之 右移 >>(相当于除以2) 左移 << ( 相当于乘以2 )。

void my_swap(int &a, int &b)
{
        a = a ^ b;
b = a ^ b;
a = a ^ b;
}


/*

基本函数说明及复杂度分析如下:

  heap_down_adjust() 从第一个不满足堆的结点s开始向下做调整,使得维护一个堆,删除栈顶元素或者建立初始堆。

  --------log(n)

heap_up_adjust() 从最后一个结点s开始向上做调整,使得维护一个堆,插入新元素的过程。

  --------log(n)

  en_heap_queue() 从尾部增加一个叶子节点到堆中,因为原本是满足堆的,所以只需要从下至上不断跟父结点进行交换,直至已满足堆退出,调用的heap_up_adjust() 

  --------log(n)

  de_heap_queue() 把start跟end做交换,然后[start,end-1]从新做一次调整,使得[start,end-1]维护成一个堆,堆大小length随之-1,调用的heap_down_adjust() 。

  --------log(n)

  heap_init() 从第一个非终端结点开始->根节点不断做heap_adjust(),使之构成一个初始堆。

  --------n / 2 * log(n)

  heap_sort()  相当于重复n次de_heap_queue()操作,但length不改变。

  --------n * log(n)

  用类模板实现,参照 :http://www.cnblogs.com/slave_wc/archive/2010/12/23/1915293.html

*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值