这几天有点抵触情绪,看过了快速排序还有一些别的东西,但是一点都不想写有点复杂的代码0 0拖到了今天终于写了前几天就应该自己写一下的堆排序,完全用C语言写的,下面把代码贴一下。很多地方写得并不好,不过已经经过了测试,可以正确运行。
1 /*堆排序*/ 2 void percolateDown(int* A, int i, int n)//下滤操作 3 { 4 while (i <= ((n - 1) - 1) / 2) 5 { 6 int rc = 2 * i + 2, lc = 2 * i + 1; 7 if (rc < n)//如果右孩子存在 8 { 9 int j = ((A[rc] > A[i]) ? ((A[rc] > A[lc]) ? rc : lc) : ((A[lc] > A[i]) ? lc : i)); 10 if (i == j) break; 11 swap(A[j], A[i]); 12 i = j; 13 } 14 else if(lc < n)//仅有左孩子(只有最后一个内部节点可能会这种情况) 15 { 16 if (A[i] >= A[lc]) break; 17 if (A[i] < A[lc]) 18 { 19 swap(A[i], A[lc]); 20 i = lc; 21 } 22 } 23 else 24 break; 25 } 26 } 27 void buildHeap(int* A, int n)//将数组就地建堆 28 { 29 for (int i = ((n - 1) - 1) / 2; (i >= 0) && (i < n); i--)//从最后一个内部节点的位置开始 30 percolateDown(A, i, n); 31 } 32 int delMax(int* A,int n)//删除最大元素,调用者自行更改规模 33 { 34 int max = A[0]; 35 A[0] = A[n - 1]; 36 percolateDown(A, 0, n - 1); 37 return max; 38 } 39 void heapSort(int* A, int n)//堆排序主算法 40 { 41 buildHeap(A, n);//就地建堆 42 while(n > 0) 43 { 44 A[n - 1] = delMax(A, n);//等价于交换未排序序列的末元素与堆顶最大元素 45 n--; 46 } 47 }
建堆是最为关键的环节,可以说堆建好了才能开始进行排序。这里为了保持高效,建堆采用的是Floyd就地建堆算法,就是从原数组最后一个内部节点的位置进行下滤操作,当下滤到外部节点或x,x->lc,x->rc节点中最大的就是x节点时,下滤结束,继续进行下一个节点的下滤。每次交换元素后,新的堆顶并不是一个合格的堆顶,因此需要对堆顶继续进行下滤操作,不过注意到,只有堆顶一个节点是不合适的,所以重新建堆的操作复杂度不超过O(logn),即堆的高度。
后面可能还会写一个K-选取的问题,即选取数组中第K大的元素,或者选取前K大的元素这种问题。基于优先级队列的方法,是一个可行的解,不过最坏情况的复杂度并不让人满意。
时间: 2024-10-11 01:46:35