堆排序 Heap Sort
作者:互联网
堆和优先队列 Heap and priority Queue
❓什么是优先队列?
普通队列:先进先出,后进后出
优先队列:出队顺序和入队顺序无关,和优先级相关
❓为什么使用优先队列?
在1,000,000个元素中选出前100名?
抽象:在N个元素中选出前M个元素
排序?NlogN
使用优先队列?NlongM
❓优先队列主要操作?
入队
出队:取出优先级最高的元素
❓优先队列的实现?
【注】使用堆实现优先队列对于总共有N个请求:
使用普通数组或者顺序数组,最差情况:O(N2)
使用堆:O(nlgn)
堆的基本存储
【特点】
(1)堆中某个节点的值总是不大于其父节点的值
(2)堆总是一棵完全二叉树(最大堆)
【注】所谓完全二叉树就是,这是一棵二叉树,对于这个二叉树,除了最后一层节点之外,其他每层节点个数必须是最大值,在最后一层虽然节点个数不是最大值,但是必须都位于最左侧,如下图所示。
【代码】
#include <iostream>
#include <algorithm>
#include <string>
#include <ctime>
#include <cmath>
#include <cassert>
using namespace std;
template <typename Item>
class MaxHeap {
private:
Item* data;
int count;
public:
MaxHeap(int capacity) {
data = new Item[capacity + 1];
count = 0;
}
~MaxHeap() {
delete [] data;
}
//堆里有多少元素
int size() {
return count;
}
//判断堆是否为空
bool isEmpty() {
return count == 0;
}
};
int main() {
MaxHeap<int> maxheap = MaxHeap<int>(100);
cout << maxheap.size() << endl;
return 0;
}
Shift up
添加一个元素相当于在数组的末尾添加一个元素(52),相应的堆如下图所示,此时是不满足最大堆的定义的,因为52比其父节点16还要大,违背了定义,所以接下来要进行一系列的操作维护堆的定义。
首先,52和16节点交换位置。
同理,52和41节点也需要交换位置。
最终52上升到了满足最大堆定义的位置,这个过程叫做Shift up过程。
【代码实现】
#include <iostream>
#include <algorithm>
#include <string>
#include <ctime>
#include <cmath>
#include <cassert>
using namespace std;
template <typename Item>
class MaxHeap {
private:
Item* data;
int count;
int capacity;
void shiftUp(int k) {
while(k > 1 && data[k/2] < data[k]) {
swap(data[k/2], data[k]);
k /= 2;
}
}
public:
MaxHeap(int capacity) {
data = new Item[capacity + 1];
count = 0;
this->capacity = capacity;
}
~MaxHeap() {
delete [] data;
}
//堆里有多少元素
int size() {
return count;
}
//判断堆是否为空
bool isEmpty() {
return count == 0;
}
//向堆中插入一个元素
void insert(Item item) {
assert(count + 1 <= capacity);
data[count+1] = item;
count++;
shiftUp(count);
}
};
int main() {
MaxHeap<int> maxheap = MaxHeap<int>(100);
cout << maxheap.size() << endl;
//随机添加15个元素,打印出来会发现这个树满足最大堆的性质
srand(time(NULL));
for(int i = 0; i < 15; i++)
maxheap.insert(rand()%100);
return 0;
}
Shift down
对于堆来说,只能取出根节点的那个元素,即最大堆只能取出优先级最高的那个元素。
为了维持最大堆的性质,把最后一个元素移动到根节点的位置,相应的记录堆元素个数的count的值要减1,此时满足完全二叉树的性质,但不是最大堆,需要进行Shift Down操作。
首先,16要和52或30交换位置,因为52大于30,所以和52交换位置。
同理,继续上面的操作,直到满足最大堆性质。
【代码实现】
#include <iostream>
#include <algorithm>
#include <string>
#include <ctime>
#include <cmath>
#include <cassert>
using namespace std;
template <typename Item>
class MaxHeap {
private:
Item* data;
int count;
int capacity;
void shiftUp(int k) {
while(k > 1 && data[k/2] < data[k]) {
swap(data[k/2], data[k]);
k /= 2;
}
}
void shiftDown(int k) {
while(2 * k <= count) {
int j = 2 * k;
if(j + 1 <= count && data[j + 1] > data[j])
j += 1;
if(data[k] >= data[j])
break;
swap(data[k], data[j]);
k = j;
}
}
public:
MaxHeap(int capacity) {
data = new Item[capacity + 1];
count = 0;
this->capacity = capacity;
}
~MaxHeap() {
delete [] data;
}
//堆里有多少元素
int size() {
return count;
}
//判断堆是否为空
bool isEmpty() {
return count == 0;
}
//向堆中插入一个元素
void insert(Item item) {
assert(count + 1 <= capacity);
data[count+1] = item;
count++;
shiftUp(count);
}
//从堆中删除一个元素
Item extractMax() {
assert(count > 0);
Item ret = data[1];
swap(data[1], data[count]);
count--;
shiftDown(1);
return ret;
}
};
int main() {
MaxHeap<int> maxheap = MaxHeap<int>(100);
cout << maxheap.size() << endl;
//随机添加15个元素,打印出来会发现这个树满足最大堆的性质
srand(time(NULL));
for(int i = 0; i < 15; i++)
maxheap.insert(rand()%100);
while(!maxheap.isEmpty()) {
cout << maxheap.extractMax() << " ";
}
cout << endl;
return 0;
}
标签:Sort,count,capacity,int,MaxHeap,堆排序,Heap,include,data 来源: https://blog.csdn.net/weixin_41462017/article/details/104789575