堆的向下调整(sift函数)
void sift(int li[], int low, int high) { /* * sift:堆的向下调整函数 * li:列表 * low:堆的根节点(堆顶) * high:堆的最后一个元素 */ int i = low;// i最开始指向的是根节点,i也是一层的父节点 int j = 2 * i + 1;// j开始是指向左孩子,注意左右孩子节点与父节点的关系 int tmp = li[low];// 把堆顶元素存起来 while (j <= high)// 只要j位置有数 { if (j + 1 <= high && li[j + 1] > li[j])// 如果右孩子存在并且比左孩子大 { j = j + 1;// j指向右孩子 } if (li[j] > tmp) { li[i] = li[j]; i = j;// 往下看一层 j = 2 * i + 1; } else// tmp更大,把tmp放到i的位置(父节点) { li[i] = tmp;// 把tmp放到某一级领导位置上——while循环结束后也会执行这一条,可以省略掉,但不方便理解 break; } } li[i] = tmp;// 存在一种情况,一直找到最后一个元素,把tmp放在叶子节点 }
堆排序过程
1.建立堆。
2.得到堆顶元素,为最大元素。
3.去掉堆顶,将堆最后一个元素放到堆顶,此时可通过一次调整重新使堆有序。
4.堆顶元素为第二大元素。
5.重复步骤3,直到堆变空。
时间复杂度:
- sift函数:O(logn)
- heap_sort函数:O(nlogn)
#include<stdio.h> void Print(int li[], int n) { int i = 0; for (i = 0; i < n; i++) { printf("%d ", li[i]); } printf("\n"); } void sift(int li[], int low, int high) { /* * sift:堆的向下调整函数 * li:列表 * low:堆的根节点(堆顶) * high:堆的最后一个元素,high的作用就是判断访问有没有越过边界 */ int i = low;// i最开始指向的是根节点,i也是一层的父节点 int j = 2 * i + 1;// j开始是指向左孩子,注意左右孩子节点与父节点的关系 int tmp = li[low];// 把堆顶元素存起来 while (j <= high)// 只要j位置有数 { if (j + 1 <= high && li[j + 1] > li[j])// 如果右孩子存在并且比左孩子大 { j = j + 1;// j指向右孩子 } if (li[j] > tmp) { li[i] = li[j]; i = j;// 往下看一层 j = 2 * i + 1; } else// tmp更大,把tmp放到i的位置(父节点) { li[i] = tmp;// 把tmp放到某一级领导位置上——while循环结束后也会执行这一条,可以省略掉,但不方便理解 break; } } li[i] = tmp;// 存在一种情况,一直找到最后一个元素,把tmp放在叶子节点 } void heap_sort(int li[], int n) { /* *n:列表长度,n-1可得到最后一个元素的访问下标 * */ int i = 0; //建堆 for (i = (n - 2) / 2; i >= 0; i--)// (n-2)/2通过孩子节点找父节点 { //i 代表建堆的时候调整的部分(子堆)的根的下标 sift(li, i, n - 1);// 传递给high的是n-1,high的作用只是判断访问不能越界即可 } //建堆完成 Print(li, n);//验证 for (i = n - 1; i >= 0; i--) { //i 指向当前堆的最后一个元素 int tmp = li[0]; li[0] = li[i]; li[i] = tmp; sift(li, 0, i - 1);// i-1是新的high } Print(li, n);//验证 } int main() { int li[] = { 5,8,2,3,7,9,6,1,4,0 }; int n = sizeof(li) / sizeof(li[0]); Print(li, n);//验证 heap_sort(li, n); return 0; }
堆排序(Heap Sort)
最新推荐文章于 2024-07-14 17:43:36 发布