堆和优先队列
什么是优先队列
普通队列:先进先出,后进后出
优先队列:出队顺序和入队顺序无关,和优先级相关
优先队列的主要操作
入队
出队(取出优先级最高的元素)
堆的基本实现
- 堆中某个节点的值总是不大于其父节点的值(最大堆)
- 总是一颗完全二叉树(允许最后一层可以不完全,但是必须全都集中在左侧)
0节点为空
p a r e n t ( i ) = i / 2 parent(i)=i/2 parent(i)=i/2
l e f t c h i l d ( i ) = 2 left child(i)=2 leftchild(i)=2 i i i
r i g h t c h i l d ( i ) = 2 right child(i)=2 rightchild(i)=2 i + 1 i+1 i+1
最大堆定义代码:
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的过程:
将元素插入最后一个节点处,然后和其父节点比较,如果比父节点大,就和父节点交换位置
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(Iten item) {
assert(count + 1 <= capacity);
data[count + 1] = item; //索引从1开始
count++;
shiftUp(count);
}
};
int main()
{
MaxHeap<int> maxheap = MaxHeap<int>(100);
cout << maxheap.size() << endl;
srand(time(NULL));
for (int i = 0; i < 15; i++)
maxheap.insert(rand() % 100);
return 0;
}
从堆中取出一个元素 shift down
取出根节点的一个元素,我们把堆中最后一个元素补到该节点,然后和子节点比较,谁大和谁换,这样才能保证根节点的数值大于子节点
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;//在此轮循环 中,data[k]和data[j]交换位置
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(Iten item) {
assert(count + 1 <= capacity);
data[count + 1] = item; //索引从1开始
count++;
shiftUp(cou nt);
}
Item extractMax() {
assert(count > 0);
Item ret = data[1];
swap(data[1], data[count]);
count--;
shiftDown(1);
return ret;
}
};
堆排序:
template<typename T>
void heapSort1(T arr[], int n) {
MaxHeap<T> maxheap = MaxHeap<T>(n);
for (int i = 0; i < n; i++)
maxheap.insert(arr[i]);
for (int i = n - 1; i >= 0; i--)
arr[i] = maxheap.extractMax(); //把它重新写入arr这样就从小到大排序完成
}
原地堆排序
用数组存储二叉堆
p
a
r
e
n
t
(
i
)
=
(
i
−
1
)
/
2
parent(i)=(i-1)/2
parent(i)=(i−1)/2
l
e
f
t
c
h
i
l
d
(
i
)
=
2
left child(i)=2
leftchild(i)=2
i
+
1
i+1
i+1
r
i
g
h
t
c
h
i
l
d
(
i
)
=
2
right child(i)=2
rightchild(i)=2
i
+
2
i+2
i+2
最后一个非叶子节点的索引:
(
c
o
u
n
t
−
1
)
/
2
(count-1)/2
(count−1)/2
template<typename T>
void _shiftDown(T arr[], int n, int i) {
while (2 * k + 1 <= n) {
int j = 2 * k+1;//在此轮循环 中,arr[k]和arr[j]交换位置
if (j + 1 <= count&&arr[j + 1] > arr[j])
j += 1;
if (arr[k] >= arr[j])
break;
swap(arr[k], arr[j]);
k = j;
}
}
template<typename T>
void heapSort(T arr[], int n) {
//heapify 把数组构建成一个堆
for (int i = (n - 1) / 2; i >= 0; i--)
_shiftDown(arr, n, i);
for (int i = n - 1; i > 0; i--) {
swap(arr[0].arr[i]);
_shiftDown(arr, i, 0);
}
}