c语言随机数堆排序,堆排序——c语言实现

本文详细介绍了堆排序算法的原理和步骤,包括如何构建大根堆、交换堆顶元素以及调整堆的过程。并通过C语言实现了一个完整的堆排序函数,实现了从输入的一组无序数字到有序序列的转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

从键盘任意输入一组数, 比如:3216549870。要求对它进行排序,使它顺序排列。

我理解的堆排序思路如下:

NO.1 首先想着让这组数按下面这种方式形成完全二叉树树型结构。

b2bd7bf2ceb5a357e371c6983147d6c3.png

A

我先给出这棵完全二叉树所具备的一些基本性质:

a: 不管这组数是奇数个还是偶数个,假设总数为count,倒数第一个非叶子节点的下标总是 count / 2 - 1。 (你可以列举奇数个试一下)

b: 叶子节点下标都大于count / 2 - 1,小于count。

c: 左孩子的下标 = 父节点下标 * 2 + 1。右孩子的下标 = 父节点下标 * 2 + 2。

NO.2 接着通过调整上面的树来构造大根堆(所有父节点的值都比其左右孩子值大的完全二叉树),步骤如下(若题目要求逆序排列,则构造小根堆,两者思路很相似):

第一步:对树A的倒数第一层处理 。先比较0和5的值,5大于0,则不动;接着比较8和7,8大于7,用8(8与7中更大的)和6比较,8大于6,交换8和6,这样交换是为了把尽可能大的数往上移动。在交换完毕后,6处于叶子节点位置,最后一层便调整完毕了,得到下面树B:(此步其实处理了下标为4和3的元素,使其分别形成大根堆,没明白先往下看)

d96aac270a212f37afc85f6a35a28c4e.png

B

第二步:对树B倒数第二层进行处理。先比较4和9,9大于4,用9和1比较,9大于1,交换9和1;接着比较8和5,8大于5,用8和2比较,8大于2,交换8和2,因为在8和2交换后,2处于非叶子节点位置,所以应将6,7中更大的那个数和2比较,7大于2,交换7和2,交换完毕后,2处于叶子节点位置,本层便处理完毕。得到下面这棵树:(此步其实处理了下标为2和1的元素,使其分别形成大根堆)

dbd7ca63c317de37fdab851a853eb12a.png

C

第三步:处理第二层(对第2步调整后的树处理),比较8和9,9大于8,用9和3比较,9大于3,交换9和3,此时,因为在9和3交换后,3处在非叶子节点位置,所以应用4(4与1中更大的)和3比较,4大于3,交换4和3,交换完毕后,3处于叶子节点位置,本层调整完毕。得到下面这棵树:(此步其实处理了下标为0的元素,使其形成大根堆)

e7b314796264e82261a98f3ba1a2918f.png

这棵树便成了大根堆。 上面便是构造大根堆的过程。

NO.3 因为在上面这大根堆中,9(这组数中最大的)的位置恰好是下标为0的,交换9和最末尾的0,便把最大值放到最末尾了。

c3ac2ed809c17e4fb3215f004c041883.png

NO.4  接着把上面这棵树继续调整为大根堆(9不用考虑),调整思路很简单:从下标为0的位置,即0所处位置开始,往下调整,直到调整到叶子节点为止。

调整过程: 比较8和4,8大于4,用8和0比较,8大于0,交换8和0,因为8和0交换,0处在非叶子节点位置,所以应用7(7,5中更大的那个数)和0比较,7大于0,交换7和0,交换完毕后,0仍处在非叶子节点位置,继续往下比较,最终得到下面这棵树(也是大根堆):

b9548daadb5638c202f6154f6d355c3f.png

接着交换8(下标为0的)和2(倒数第二个),再忽略8,继续构造大根堆,大根堆构造好了交换下标为0的和倒数第三个,依次循环,直到可忽略的数字为这组数总数减1时停下,此时,你会发现这组数已经顺序排列了!

现在我希望你能把这堆排序的整个思路串起来想一下。

第一步:形成树(当然此步不需要任何操作)。

第二步:构造大根堆。

第三步:交换下标为0和末尾的,交换后使末尾往前移动一位(--count 实现)。

第四步:从下标为0的往下调整,继续形成大根堆。

第五步:重复第三步和第四部,直到末尾移动到下标为0处,便顺序了。

稍加思考发现,思路可以更简便些,上面第二步可以修改为:停留在第一次刚好形成大根堆的前一步,然后紧接着做第四步,然后做第三步,再四三四三步循环。

现在最终思路出来了!

第一步:形成树(当然此步不需要任何操作)。

第二步:停留在构造成功大根堆的前一步。

第三步:从下标为0的往下调整,形成大根堆。

第四步:交换下标为0和末尾的,交换后使末尾往前移动一位(--count 实现)。

第五步:重复第三步和第四部,直到末尾移动到下标为0处,便顺序了。

开始贴代码了:

#include

#include

void adjuctHeap(int theFinalNoLeaveNodeIndex, int *arr, int count);

void heapSort(int *arr, int count);

void adjuctHeap(int i, int *arr, int count) {int tmp;

int max;

while(i <= count / 2 - 1) { // 条件判断检测是否到了叶子节点

tmp = 2 * i + 2 >= count ? 0 : arr[2 * i + 2]; //总数为偶数,最后一个父节点没有右孩子

max = arr[2 * i + 1] >= tmp ? 2 * i + 1 : 2 * i + 2; //max值:左右孩子中更大的那个孩子节点的下标

if(arr[max] > arr[i]) {

tmp = arr[max];

arr[max] = arr[i];

arr[i] = tmp;

i = max;

}

else

break;

}

}

void heapSort(int *arr, int count) {

int i;

int tmp;for(i = count / 2 - 1; i > 0; i--) { // 停留在构造成功大根堆的前一步。 count / 2 - 1 表示倒数第一个非叶子节点。

adjuctHeap(i, arr, count);

}

while(count > 1) {

adjuctHeap(0, arr, count); // 构造大根堆

tmp = arr[0];

arr[0] = arr[count - 1]; // 交换

arr[count - 1] = tmp;

--count; // 末尾往前移动

}

}

int main() {

int i;

int *arr;

int count;

printf("please input the count of numbers:");

scanf("%d", &count);

arr = (int *) calloc(sizeof(int), count);

printf("please input the numbers:");

for(i = 0; i < count; i++) {

scanf("%d", &arr[i]);

}

heapSort(arr, count);

for(i = 0; i < count; i++) {

printf("%d ", arr[i]);

}

printf("\n");

free(arr);

return 0;

}

结果

please input the count of numbers:10

please input the numbers:3 2 1 6 5 4 9 8 7 0

0 1 2 3 4 5 6 7 8 9

标签:count,大根堆,arr,下标,语言,实现,交换,堆排序,int

来源: https://www.cnblogs.com/zss222325/p/10498391.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值