堆的定义以及堆排序


🚗前言

本人是西安邮电大学的一个普通的 大学生,如果这篇文章对你有帮助的话请给我点个赞吧,球球了。
请添加图片描述


🎉堆的概念

直接上图

在这里插入图片描述

其实可以把堆看成一个完全二叉树,并且用数组实现。
左右孩子和双亲的关系就是这样的:
leftchild=parent*2+1;
rightchild=parent *2+2;
parent = (child-1)/2;


✈️堆的代码实现

heap.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<windows.h>
#include<stdbool.h>
#include<assert.h>
#include<stdlib.h>

typedef int HPDataType;

typedef struct Heap
{
HPDataType* a;
size_t size;
size_t capacity;
}HP;

void Swap(HPDataType* pa, HPDataType* pb);
void HeapInit(HP* php);
void HpDestroy(HP* php);
void HeapPrint(HP* php);

// 插入x以后,保持他依旧是(大/小)堆
void HeapPush(HP* php, HPDataType x);

// 删除堆顶的数据。(最小/最大)
void HeapPop(HP* php);
bool HeapEmpty(HP* php);
size_t HpSize(HP* php);
HPDataType HeapTop(HP* php);

heap.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#define _CRT_SECURE_NO_WARNINGS 1
#include"heap.h"

void AdjustUp(HPDataType* a, size_t child)//看是大堆还是小堆,大堆父母比孩子大,小堆父母比孩子小
{
size_t parent = (child - 1) / 2;
while (child > 0)
{
if (a[child]>a[parent])
{
Swap(&a[parent], &a[child]);//要传地址
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}

//看是大堆还是小堆,大堆父母比孩子大,小堆父母比孩子小
void AdjustDown(HPDataType* a, size_t size, size_t root)
{
size_t parent = root;
size_t child = parent * 2 + 1;
while (child<size)
{
if (child + 1 < size && a[child + 1] > a[child])
{
child++;
}

if (a[child] > a[parent])
{
Swap(&a[parent], &a[child]);//要传地址

parent = child;
child = parent*2+1;
}
else
{
break;
}
}
}

void Swap(HPDataType* pa, HPDataType* pb)
{
HPDataType tmp = *pa;
*pa = *pb;
*pb = tmp;
}


void HeapInit(HP* php)
{
assert(php);
php->a = NULL;
php->size = 0;
php->capacity = 0;
}



void HeapPrint(HP* php)
{
assert(php);
size_t i = 0;
for (i = 0; i<php->size; i++)
{
printf("%d ",php->a[i] );
}
printf("\n");
}



// 插入x以后,保持他依旧是(大/小)堆
void HeapPush(HP* php, HPDataType x)
{
assert(php);
if (php->capacity == php->size)
{
size_t newcapacity = php->capacity==0?4:(php->capacity*2);
HPDataType* tmp = (HPDataType*)realloc(php->a,sizeof(HPDataType)*newcapacity);//注意是realloc不是malloc
if (tmp == NULL)
{
printf("malloc failed\n");
exit(-1);
}
php->a = tmp;
php->capacity = newcapacity;
}
php->a[php->size] = x;
php->size++;

AdjustUp(php->a, php->size - 1);
}

void HpDestroy(HP* php)
{
assert(php);
free(php->a);
php->a = NULL;
php->size = 0;
php->capacity = 0;
}

// 删除堆顶的数据。(最小/最大)
void HeapPop(HP* php)
{
assert(php);
assert(php->size > 0);
Swap(&php->a[0], &php->a[php->size - 1]);
php->size--;
AdjustDown(php->a,php->size,0);
}

bool HeapEmpty(HP* php)
{
assert(php);
return php->size == 0;
}

size_t HpSize(HP* php)
{
assert(php);
return php->size;
}

HPDataType HeapTop(HP* php)
{
assert(php);
assert(php->size > 0);

return php->a[0];
}

test.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void test1()
{
HP hp;
HeapInit(&hp);
HeapPush(&hp, 1);
HeapPush(&hp, 5);
HeapPush(&hp, 0);
HeapPush(&hp, 8);
HeapPush(&hp, 3);
HeapPush(&hp, 9);
HeapPush(&hp, 6);
HeapPush(&hp, 7);
HeapPrint(&hp);
HeapPop(&hp);
HeapPrint(&hp);
HpDestroy(&hp);
}
int main(void)
{
test1();
return 0;
}

🏍️堆排序

代码实现

这里用的是向上调整建大堆,然后进行堆排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
void Swap(HPDataType* pa, HPDataType* pb)
{
HPDataType tmp = *pa;
*pa = *pb;
*pb = tmp;
}
void AdjustUp(HPDataType* a, size_t child)//看是大堆还是小堆,大堆父母比孩子大,小堆父母比孩子小
{
size_t parent = (child - 1) / 2;
while (child > 0)
{
if (a[child]>a[parent])
{
Swap(&a[parent], &a[child]);//要传地址
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}

//看是大堆还是小堆,大堆父母比孩子大,小堆父母比孩子小
void AdjustDown(HPDataType* a, size_t size, size_t root)
{
size_t parent = root;
size_t child = parent * 2 + 1;
while (child<size)
{
if (child + 1 < size && a[child + 1] > a[child])
{
child++;
}

if (a[child] > a[parent])
{
Swap(&a[parent], &a[child]);//要传地址

parent = child;
child = parent*2+1;
}
else
{
break;
}
}
}

void HeapSort(int* a, int n)
{
int i = 1;
for (i = 1; i < n; i++)
{
AdjustUp(a, i);
}
int end = n - 1;
while (end>0)
{
Swap(&a[0],&a[end]);
AdjustDown(a, end, 0);
end--;
}
}
int main(void)
{
int a[10] = { 5,2,4,6,3,7,8,9,1,0 };
HeapSort(a, sizeof(a)/sizeof(a[0]));
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ",a[i]);
}
return 0;
}

在这里插入图片描述


🎉结语

既然都看到这里了就点个赞再走呗

请添加图片描述
在这里插入图片描述


堆的定义以及堆排序
https://6jackjiang.github.io/2022/04/17/categories/C语言/堆的定义以及堆排序/
作者
米兰的小铁匠
发布于
2022年4月17日
许可协议