文章目录
堆排序
想要了解堆排序,最好先掌握堆的基本操作。
-
思路
思考取出堆元素的操作,每取出一个元素,堆里面的元素就减少一个,但是存储堆元素的数组空间大小是不变的。所以可以把一个元素从堆取出后,将其存储在堆中最后一个元素后面。 -
步骤
- 用待排序数组建立一个没有“哨兵”的最大堆(即存储堆元素的数组从下标为0的位置开始存储)。
- 取出最大堆中一个元素,该元素一定是堆中元素最大的。然后将该元素存储在存储最大堆元素的数组的下标为MaxHeap->Size的位置。
- 重复执行第二步,直到堆中只剩一个元素。
-
伪码描述
void HeapSort(ListElementType *A,int Size) { H = BuildMaxHeap(A,Size); /* 将数组A建成没有“哨兵”的最大堆 */ for(;H->Size > 1;) { Temp = DeleteMaxHeap(H); /* 一直取出最大堆中最大的元素,直到堆中只剩一个元素 */ H->Data[H->Szie] = Temp; /* 取出的元素放在最后堆最后一个元素的后面 */ } }
-
代码实现
/* 堆排序 */ void HeapSort(ListElementType *A, int Size) { int HeapSize = Size; int child = 0, parent = 0; ListElementType Temp; /* 将数组A元素排序,建成最大堆 */ for (parent = (Size - 1) / 2; parent >= 0; parent--) { Temp = A[parent]; for (; (parent * 2 + 1) <= (HeapSize-1); parent = child) { child = parent * 2 + 1; /* child指向parent的左孩子 */ /* 比较parent左右孩子的大小,child指向左右孩子中值比较大的那个 */ if (child != (HeapSize-1) && (A[child] < A[child + 1])) { child++; } /* 两个子节点中最大的那个和父节点进行比较,如果子节点比较大,就将子节点和父节点互换位置;如果父节点比较大则跳出循环 */ if (Temp < A[child]) { A[parent] = A[child]; } else { break; } } A[parent] = Temp; } /* 取出堆中最大值,并将其放在堆最后一个元素后面 */ while (HeapSize > 1) { Swap(&A[0], &A[HeapSize-1]); HeapSize--; Temp = A[0]; for (parent = 0; (parent * 2 + 1) <= (HeapSize-1); parent = child) { child = parent * 2 + 1; /* child指向parent的左孩子 */ /* 比较parent左右孩子的大小,child指向左右孩子中值比较大的那个 */ if (child != (HeapSize-1) && (A[child] < A[child + 1])) { child++; } /* 两个子节点中最大的那个和父节点进行比较,如果子节点比较大,就将子节点和父节点互换位置;如果父节点比较大则跳出循环 */ if (Temp < A[child]) { A[parent] = A[child]; } else { break; } } A[parent] = Temp; } }
-
时间复杂度
平均时间复杂度: T a v g ( N ) = O ( N log N ) T_{avg}(N)=O(N \log N) Tavg(N)=O(NlogN) -
稳定性
堆排序是不稳定排序。