【总结笔记】快排与堆排
快速排序 【不稳定算法】
- 1)要有哨兵,左右指针指向的值都是跟哨兵比较;
- 2)里边两个while都不能等于,才能实现右边调换后,从左边开始找起,左边调用后,从右边找起;
- 3)二分时,一定是 quickSort(vec, startId, left-1); quickSort(vec, left+1, endId);
不能包括中分节点,否则会出现无休止递归,陷入递归栈爆的问题。 - 4)在循环里面,当前的 left/right 就是哨兵的预位置,该当该位置的左边都小于哨兵,右边都大于等于哨兵时,才将哨兵安顿下来。
- 【非稳定算法】将序列分成两段,比大于等于哨兵的放右边,小于哨兵的放左边。因此当有重复元素,以两个连续的5为例子,当left移动到第一个5时,会将其换到右边的子序列。因此快速排序不是稳定的算法。
void quickSort(vector<int> &vec, int startId, int endId) {
if (startId >= endId)
return;
int left = startId, right = endId;
int soldier = vec[left], tmp;
while (left < right) {
while (left < right && vec[right] >= soldier) // 大于等于target放右边
--right;
if (left < right)
vec[left++] = vec[right];
while (left < right && vec[left] < soldier) // 小于target放左边
++left;
if (left < right)
vec[right--] = vec[left];
}
vec[left] = soldier;
quickSort(vec, startId, left-1);
quickSort(vec, left+1, endId);
}
int main()
{
int arr[] = {5,3,7,6,4,1,0,2,9,5,8};
vector<int> vec;
for (auto data : arr)
vec.push_back(data);
int length = vec.size();
quickSort(vec, 0, length-1);
for (auto data : vec)
cout << data << " ";
return 0;
}
215 数组中的第 K 个最大元素
基于快排求第 K 个最大元素,首先可以无需对下标为 n-k 的节点的左边进行排序 if (lft>nums.size()-k) quickSort(nums, left, lft-1, k);
;
时间复杂度为 O(n) 【证明复杂,参照算法导论 9.2 期望为线性的选择算法】
空间复杂度位O(logn) 【递归栈的高度】
堆排序 【不稳定算法】
堆排序的精髓之处是基于数组,以下标为 i 的元素为堆顶,其左孩子下标为 2*i + 1,右孩子下标为 2*i + 2。
堆排序算法过程:
(1)建大/小顶堆:以第 n/2..1 个结点为堆顶进行最大堆化处理。
(2)将堆顶元素(下标为0)与堆尾元素(下标为 heapsize-1)互换,每交换1次,堆尾下标减1,直到所有元素排序完毕
- 重点:最大堆化处理算法
若左右孩子的最大值大于堆顶,则将其与堆顶元素交换。由于交换后会破坏以最大孩子结点为堆顶的堆的最大堆性质,因此,还要对最大孩子结点进行堆调整。
值得注意的是,需要判断左右孩子是否不在给定的堆大小范围内。
215 数组中的第 K 个最大元素
class Solution {
private:
void buildMaxHeap(vector<int>& nums, int heapSize) {
for (int curId=heapSize/2; curId>=0; --curId) {
maxHeapify(nums, heapSize, curId);
}
}
void maxHeapify(vector<int>& nums, int heapSize, int parent) {
int lchild = 2*parent + 1, rchild = 2*parent + 2, maxPtr = parent;
if (lchild < heapSize && nums[lchild] > nums[maxPtr])
maxPtr = lchild;
if (rchild < heapSize && nums[rchild] > nums[maxPtr])
maxPtr = rchild;
if (maxPtr != parent) {
swap(nums[parent], nums[maxPtr]);
maxHeapify(nums, heapSize, maxPtr);
}
}
public:
int findKthLargest(vector<int>& nums, int k) {
int n = nums.size(), cnt = 0;
int heapSize = n;
buildMaxHeap(nums, heapSize);
for (int i=n-1; i>=0 && cnt<k; --i,++cnt) {
swap(nums[0], nums[i]);
--heapSize;
maxHeapify(nums, heapSize, 0);
}
return nums[n-k];
}
};
时间复杂度为 O(nlogn) —— 参照算法导论
空间复杂度为 O(n) —— 递归栈大小等于树的高度