堆排序的实现与优先队列相似。本文先给出堆排序代码,然后对其中要点进行解释,程序中的注释已经很详细了。接着,给出一个应用对排序的编程题(华为笔试题)。
实例:从小标0开始存放数据,利用数组实现大顶堆,从而实现堆排序。
#include <iostream>
using namespace std;
#define ElementType int
void showFunc(ElementType a[], int N)
{
for (int i = 0; i < N; i++)
cout << a[i] << ' ';
cout << '\n';
}
//堆有序函数:保证以i为根节点的树有序
void AdjustDown(ElementType arr[],int i,int N)
{
int child;
ElementType tmp;
for (tmp = arr[i]; 2 * i + 1 < N; i = child)
{
child = 2 * i + 1; //i节点的左子节点
//i节点有两个子节点,选择其中元素值大的节点
if (child != N - 1 && arr[child + 1] > arr[child])
child++;
//父节点i与子节点比较,判断父节点是否需要下沉(另一种说法,是否在子节点中产生空穴)。
if (tmp < arr[child]) //因为使用赋值方法,故每次父节点与子节点值相同,故这里必须与原子节点tmp比较。
arr[i] = arr[child]; //使用赋值的方法产生空穴。
else
break;
}
arr[i] = tmp;
}
//将元素按大顶堆进行存储
void MakeHeap(ElementType arr[], int N)
{
int i = 0;
for (i = N / 2 - 1; i >= 0; i--) //从最后一个叶子节点N-1的父节点N / 2 - 1开始构造堆(从小标0开始存储的数组)
AdjustDown(arr, i, N);
}
void swap(ElementType *a, ElementType *b)
{
ElementType tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
//升序排列函数
void HeapSort(ElementType arr[], int len)
{
int i = 0;
MakeHeap(arr, len);
for (i = len - 1; i >= 0; i--)
{
swap(&arr[i], &arr[0]);
AdjustDown(arr,0,i);
}
}
int main()
{
int len = 10;
ElementType *a;
a = (ElementType *)malloc(len*sizeof(ElementType));
for (int i = 5; i >0; i--)
a[5-i] = i;
for (int i = 0; i <len; i++)
a[5 +i] = i+10;
cout << "数组原序列为: ";
showFunc(a,len);
cout << "堆有序后的数组序列为: ";
MakeHeap(a, len);
showFunc(a, len);
cout << "升序排列的数组序列为: ";
HeapSort(a,len);
showFunc(a, len);
//free(a);
system("pause");
return 0;
}
注释:
1、构造堆
将数据存放在数组中,将数组构建为大顶堆。
void MakeHeap(ElementType arr[], int N)
{
int i = 0;
for (i = N / 2 - 1; i >= 0; i--) //从最后一个叶子节点N-1的父节点N / 2 - 1开始构造堆(从小标0开始存储的数组)
AdjustDown(arr, i, N);
}
主要思路就是从最后一个二叉树构建堆。若数据从小标[0]开始存放,那可第k个结点的父结点为(k-1)/2,其结点为2k+1和2k+2。据此,最后一个叶子结点的父节点即最后一个二叉树的下标为N/2-1,N表示数据总个数。
2、排序
将大顶堆对顶数据与最后一个数据进行交换,此时,最后一个数据就是整个数据中的最大值;
经过交换后,其余数据可能已经不是堆有序的,需要重新调整,具体方法是对判断堆顶元素是否需要“下沉”,注意此时不需要考虑最后一个元素;
如此循环,得到堆排序后的数据。
for (i = len - 1; i >= 0; i--)
{
swap(&arr[i], &arr[0]);
AdjustDown(arr,0,i);
}
实例:
问题描述:输入一串以逗号分隔的字符串,将最够一个字符作为优先级,将其按优先级输出。
输入:b2,a1,a3,c5,m4
输出:c5,m4,a3,b2,a1
#include <string>
#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
void AdjustDown(vector<string> &V, int i, int N)
{
int child;
string tmp;
char tmpCh, LeftCh, RightCh;
tmp = V[i];
tmpCh = tmp[tmp.size() - 1];
for (; 2 * i + 1 < N; i = child)
{
child = 2 * i + 1;
if (child != N - 1)
{
LeftCh = V[child][V[child].length() - 1];
RightCh = V[child + 1][V[child + 1].length() - 1];
if (RightCh > LeftCh)
child++;
}
if (tmpCh < V[child][V[child].length() - 1])
V[i] = V[child];
else
break;
}
V[i] = tmp;
}
int main()
{
string str;
vector<string> V;
getline(cin, str); //因为最后一个字符没有逗号,直接使用getline(cin, str,',')读不到最后一个
istringstream is(str);
while (getline(is, str, ','))
{
V.push_back(str);
}
cout << "原始序列:" << endl;
for (int i = 0; i < V.size(); ++i)
cout << V[i] << endl;
//构建大顶堆
for (int i = V.size() / 2 - 1; i >= 0; i--)
AdjustDown(V, i, V.size());
cout << "大顶堆堆序列:" << endl;
for (int i = 0; i < V.size(); ++i)
cout << V[i] << endl;
//堆排序
for (int i = V.size() - 1; i >= 0; i--)
{
string tmp;
tmp = V[0];
V[0] = V[i];
V[i] = tmp;
AdjustDown(V, 0, i);
}
cout << "排序后的序列:" << endl;
for (int i = V.size(); i >=0; i--)
cout << V[i] << endl;
system("pause");
return 0;
}