前言:
堆的实现其实并不难,难的是要用堆实现排序,也就是堆的运用。
下面需要探究一下堆的排序是怎样的。
如何利用堆进行升序或者降序的排序。
"堆排序":
原理:
例如:此时要将数组里的数组int arr[] = {12,20,26,8,1,2,3}进行升序或者降序排序。
第一步:把数放进堆里面,但是究竟是放在大堆还是小堆里面呢?
如果需要升序就需要放进大堆里面!
如果需要降序就需要放进小堆里面!
(原因后续画图讲解)
如何将一个数组直接放在大堆当中呢?
可以直接遍历数组,将数一个一个放入。
代码如下:
typedef int HPDataType;
void AdjustUp(HPDataType* a, int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (a[child] > a[parent])
{
swap(&a[child], &a[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void HeapPush(Heap* hp, HPDataType x)
{
assert(hp);
if (hp->_capacity == hp->_size)
{
int newcapacity = hp->_capacity == 0 ? 4 : hp->_capacity * 2;
HPDataType* tmp = (HPDataType*)realloc(hp->_a, newcapacity * sizeof(HPDataType));
if (tmp == NULL)
{
perror("malloc::error");
exit(-1);
}
hp->_capacity = newcapacity;
hp->_a = tmp;
}
hp->_a[hp->_size] = x;
hp->_size++;
AdjustUp(hp->_a, hp->_size - 1);
}
void test2()
{
Heap hp;
HeapInit(&hp);
int arr[] = {12,20,26,8,1,2,3};
int i = 0;
int size = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < size; i++)
{
HeapPush(&hp, arr[i]);
}
}
此时就直接形成了”大堆“。
第二步:每次需要交换首和尾
交换之后将除了新的尾的数之外的数进行向下调整,
也就是将除了26以外的数进行向下调整:
向下调整:
第三步:以此类推,直到遍历到第一个数为止。
大家可以亲自动手画一画,很有助于理解。
我把这个方法称之为“沉淀法”!
此时最后就是一个升序的树,可以直接按照顺序打印出来。
代码如下:
void AdjustUp(HPDataType* a, int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (a[child] > a[parent])
{
swap(&a[child], &a[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void HeapPush(Heap* hp, HPDataType x)
{
assert(hp);
if (hp->_capacity == hp->_size)
{
int newcapacity = hp->_capacity == 0 ? 4 : hp->_capacity * 2;
HPDataType* tmp = (HPDataType*)realloc(hp->_a, newcapacity * sizeof(HPDataType));
if (tmp == NULL)
{
perror("malloc::error");
exit(-1);
}
hp->_capacity = newcapacity;
hp->_a = tmp;
}
hp->_a[hp->_size] = x;
hp->_size++;
AdjustUp(hp->_a, hp->_size - 1);
}
void HeapInit(Heap* hp)
{
assert(hp);
hp->_a = NULL;
hp->_capacity = hp->_size = 0;
}
void AdjustDown(HPDataType* a, int size, int parent)
{
//假设最大的孩子的值是左孩子对应的数值
int childmax = (parent * 2) + 1;
while (childmax < size)
{
//如果右有孩子并且右孩子的值是大于左孩子将最大的孩子换成右孩子
if (childmax + 1 < size && a[childmax + 1] > a[childmax])
{
childmax = childmax + 1;
}
if (a[parent] < a[childmax])
{
swap(&a[parent], &a[childmax]);
parent = childmax;
childmax = (parent * 2) + 1;
}
else
{
break;
}
}
}
void test2()
{
Heap hp;
HeapInit(&hp);
int arr[] = {12,20,26,8,1,2,3};
int i = 0;
int size = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < size; i++)
{
HeapPush(&hp, arr[i]);
}
for (i = 0; i < size; i++)
{
//交换首尾
swap(&hp._a[0], &hp._a[hp._size - 1 - i]);
//向下调整
AdjustDown(hp._a, hp._size-1-i, 0);
}
for (i = 0; i < size; i++)
{
arr[i] = hp._a[i];
}
for (i = 0; i < size; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
//test1();
test2();
return 0;
}
"十万个数据"进行堆排序:
大数据时代,如果有10万个数据要进行排序,该怎么排序。
究竟是用哪种排序的方式时间复杂度最低呢?
在这之前需要我们计算一下”堆排序“的时间复杂度!