您的位置:首页 > 理论基础 > 数据结构算法

堆的创建与应用以及堆排序

2018-01-22 19:24 225 查看
1.堆的概念:

如果有一个关键码的集合K={k0,k1,k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki<=k2*i+1且ki<=k2*+2(ki>=k2*i+1且ki>=k2*i+2)。(i=0,1,2,…)则称这个堆为最小堆(或最大堆)

堆的特性:

用来存数据——>完全二叉树形式

任意结点满足:1.leftchild=2*i+1;

2.rightchild=2*i+2;

最小堆:任一结点的关键码均小于等于它的左右孩子的关键码,位于堆顶结点的关键码最小。下图为最小堆。



最大堆:任一结点的关键码均大于等于它的左右孩子的关键码,位于堆顶结点的关键码最大。下图为最大堆。



堆的创建:

先将数组中的元素存贮起来,如下图所示。



显然其并不是最小堆或最大堆的形式,所以要进行调整。

(现调整为最小堆)

从其倒数第一个非叶子的位置开始调整,第一次:i=(8-2)/2。检测以i为根节点的子树是否满足最小堆,若满足则不进行调整,若不满足开始调整。



具体的堆的创建部分代码为:

Heap(const T*array,size_t size)//堆的创建
{
//1.将数组中的元素存起来
_array.resize(size);
for (size_t i = 0; i < size; i++)
{
_array[i] = array[i];
}
//2.向下调整
int root = (size - 2) >> 1;
for (; root >= 0; root--)
{
_AdjustDown(root);
}
}
void _AdjustDown(size_t parent)//向下调整
{
size_t child = parent * 2 + 1;
size_t size = _array.size();
while (child < size)
{
if ((child + 1 < size) && (_array[child] > _array[child + 1]))
{
child += 1;
}
if (_array[parent]>_array[child])
{
swap(_array[parent], _array[child]);
parent = child;
child = parent * 2 + 1;//继续走到其左侧,进行调整
}
else
{
break;
}
}
}


堆的插入:

堆的插入每次都是在已经建好的最小堆的后面插入,插入之后,有可能破坏堆的结构,需对堆进行调整。

调整的方法为从下向上调整,因为上面的元素已经是按照最小堆的形式列出,所以需用向上调整的方法。

具体方法为:

比较parent与child的值域,若parent值域大于child值域,则进行交换,之后再向上调整。

具体的代码为:

void Push(const T& data)
{
_array.push_back(data);
if (_array.size() > 1)
{
_AdjustUp(_array.size() - 1);
}
}
void _AdjustUp(size_t child)//向上调整
{
size_t size = _array.size();
size_t parent = (size - 2) >> 1;
while (child > 0)
{
if (_array[parent] > _array[child])
{
swap(_array[parent], _array[child]);
child = parent;
parent = (child - 1) >> 1;
}
else
{
break;
}
}
}


堆的删除:堆的删除是针对于堆顶元素,删除堆顶元素。

具体分为三种情况:

1.堆为空:则直接返回

2.堆中只有一个元素—->直接删除之后返回

3.堆中有多个元素:先将最后一个元素与堆顶元素进行交换,之后删除堆顶元素,再进行向下调整。

void Pop()
{
if (Size()==0)
return;
else
{
size_t last = _array.size() - 1;
swap(_array[0], _array[last]);
_array.pop_back();
//2.向下调整
_AdjustDown(0);
}
}


完整的代码为:

#include<iostream>
#include<vector>
using namespace std;
template<class T>
class Heap
{
public:
Heap()
{}
Heap(const T*array,size_t size)//堆的创建
{
//1.将数组中的元素存起来
_array.resize(size);
for (size_t i = 0; i < size; i++)
{
_array[i] = arra
4000
y[i];
}
//2.向下调整
int root = (size - 2) >> 1;
for (; root >= 0; root--)
{
_AdjustDown(root);
}
}
void Push(const T& data)
{
_array.push_back(data);
if (_array.size() > 1)
{
_AdjustUp(_array.size() - 1);
}
}
void Pop() { if (Size()==0) return; else { size_t last = _array.size() - 1; swap(_array[0], _array[last]); _array.pop_back(); //2.向下调整 _AdjustDown(0); } }
T Top()const
{
return _array[0];
}
bool Empty()const
{
return _array.empty();
}
size_t Size()const
{
return _array.size();
}
private:
void _AdjustDown(size_t parent)//向下调整
{
size_t child = parent * 2 + 1;
size_t size = _array.size();
while (child < size)
{
if ((child + 1 < size) && (_array[child] > _array[child + 1]))
{
child += 1;
}
if (_array[parent]>_array[child])
{
swap(_array[parent], _array[child]);
parent = child;
child = parent * 2 + 1;//继续走到其左侧,进行调整
}
else
{
break;
}
}
}
void _AdjustUp(size_t child)//向上调整
{
size_t size = _array.size();
size_t parent = (size - 2) >> 1;
while (child > 0)
{
if (_array[parent] > _array[child])
{
swap(_array[parent], _array[child]);
child = parent;
parent = (child - 1) >> 1;
}
else
{
break;
}
}
}
private:
vector<T>_array;
};
int main()
{
int array[] = { 53, 17, 78, 9, 45, 65, 87, 23 };
Heap<int>h(array, sizeof(array) / sizeof(int));
h.Push(10);
cout << boolalpha << h.Empty() << endl;
cout << h.Top() << endl;
cout << h.Size() << endl;
h.Pop();
cout << h.Size() << endl;
cout << h.Empty() << endl;
system("pause");
return 0;
}


2.给堆添加比较器,用户可以任意控制大堆或者小堆

#include<iostream>
#include<vector>
using namespace std;
template<class T>
struct Greater
{
bool operator()(const T&a, const T&b)
{
return a > b;
}
};
template<class T>
struct Smaller
{
bool operator()(const T&a, const T&b)
{
return a < b;
}
};
template<class T, class compare=Smaller<T>>
class Heap
{
public:
Heap()
{}
Heap(T*array, int size)//堆的创建
{
//1.将数组中的元素存起来
_array.resize(size);
for (int i = 0; i < size; i++)
{
_array[i] = array[i];
}
//2.向下调整
int root = (size - 2) >> 1;
for (; root >= 0; root--)
{
_AdjustDown(root);
}
}
void Push(const T& data)
{
_array.push_back(data);
if (_array.size() > 1)
{
_AdjustUp(_array.size() - 1);
}
}
void Pop()
{
if (Size()==0)
return;
else
{
int last = _array.size() - 1;
swap(_array[0], _array[last]);
_array.pop_back();
//2.向下调整
_AdjustDown(0);
}
}
T Top()const
{
return _array[0];
}
bool Empty()const
{
return _array.empty();
}
size_t Size()const
{
return  _array.size();
}
private:
void _AdjustDown(int parent)//向下调整
{
int child = parent * 2 + 1;
int size = _array.size();
while (child < size)
{
if ((child + 1 < size) && (compare()(_array[child], _array[child + 1])))
{
child += 1;
}
if (compare()(_array[parent], _array[child]))
{
swap(_array[parent], _array[child]);
parent = child;
child = parent * 2 + 1;//继续走到其左侧,进行调整
}
else
return;
}
}
void _AdjustUp(int child)//向上调整
{
int size = _array.size();
int parent = (size - 2) >> 1;
while (child > 0)
{
if (compare()(_array[parent], _array[child]))
{
swap(_array[parent], _array[child]);
child = parent;
parent = (child - 1) >> 1;
}
else
{
break;
}
}
}
private:
vector<T>_array;
};
int main()
{
int array[] = { 53, 17, 78, 9, 45, 65, 87, 23 };
Heap<int,Smaller<int>>h(array, sizeof(array) / sizeof(int));
//Heap<int, Greater<int>>h1(array, sizeof(array) / sizeof(array[0]));
h.Push(10);
cout << boolalpha << h.Empty() << endl;
cout << h.Top() << endl;
cout << h.Size() << endl;
h.Pop();
cout << h.Size() << endl;
cout << h.Empty() << endl;
system("pause");
return 0;
}


3.用堆封装优先级队列

优先级队列:priority_queue,其为0个或多个元素的集合。

#include<iostream>
#include<vector>
#include"Heap.h"
using namespace std;
template<class T,class compare>
class priority
{
public:
priority()
{}
void push(const T&data)
{
h.Push(data);
}
void pop()
{
h.Pop();
}
T Top()
{
return h.Top();
}
size_t Size()
{
return h.Size();
}

bool Empty()
{
return h.Empty();
}
private:
Heap<T, compare>h;
};
int main()
{
/*int array[] = { 53, 17, 78, 9, 45, 65, 87, 23 };
Heap<int,Smaller<int>>h(array, sizeof(array) / sizeof(int));*/
//Heap<int, Greater<int>>h1(array, sizeof(array) / sizeof(array[0]));
priority<int, Greater<int>>p;
p.push(10);
p.push(25);
cout << boolalpha << p.Empty() << endl;
cout << p.Top() << endl;
cout << p.Size() << endl;
p.pop();
cout << p.Size() << endl;
cout << p.Empty() << endl;
system("pause");
return 0;
}


4.堆排序:其为选择排序的一种,

具体步骤为:<1>创建堆

<2>调整。排序

升序:若升序时建小堆的话,下标最小的元素最小,但是每次选出最小的之后剩下的都要重新再调整为一个小堆。

若建大堆的话,根节点是最大的值,每次只要和其孩子进行交换,再进行调整。

以此结论:

升序—–>建大堆

降序——>建小堆

#include<iostream>
#include<vector>
using namespace std;
void AdjustDown(int* array, size_t size, size_t parent)
{
size_t child = parent * 2 + 1;
while (
b70d
child < size)
{
if (child + 1 < size&&array[child + 1] > array[child])
{
++child;
}
if (array[child]>array[parent])
{
std::swap(array[child], array[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}

void HeapSort(int* array, size_t size)
{
//见堆
for (int i = (size - 2) / 2; i >= 0; --i)
{
AdjustDown(array, size, i);
}
for (size_t i = 0; i < size; ++i)
{
std::swap(array[0], array[size - i - 1]);//最后一个数的下标
AdjustDown(array, size - i - 1, 0);//个数
}
}
int main()
{
int array[] = { 10, 11, 12, 14, 12, 1, 2, 3, 4, 15, 19 };
int len = sizeof(array) / sizeof(array[0]);
HeapSort(array, len);
for (size_t i = 0; i < len; ++i)
{
cout << array[i] << " ";
}
system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构
相关文章推荐