您的位置:首页 > 其它

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

2014-09-18 19:24 239 查看
/*

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

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: