选择排序:顾名思义,就是每次循环从数组[i,n)选择一个最小的元素放入位置i,一共n个元素,需要n-1轮循环。伪代码如下:
void selectionSort(ElementType A[], int N){
for(i=0; i<N; i++){
//从A[]到A[]中找最小元,并将其位置赋给MinPosition
MinPosition=scanForMin(A,i,N-1);
//将未排序部分的最小元换到有序部分的最后位置
swap(A[i],A[MinPositon]);
}
}
#include<bits/stdc++.h>
using namespace std;
int scanForMin(vector<int>& arr,int start,int end) {
int minPos = start;
for (int i = start; i <= end;i++) {
minPos = arr[i] < arr[minPos] ? i : minPos;
}
return minPos;
}
void selectionSort(vector<int>& arr) {
int n = arr.size();
int minPos = 0;
for (int i = 0; i < n; i++) {
minPos = scanForMin(arr, i, n - 1);
swap(arr[i], arr[minPos]);
}
}
int main() {
vector<int> arr = { 8,6,10,7,9,4,3,2,5,1 };
selectionSort(arr);
for (auto x : arr) {
cout << x << " ";
}
cout << endl;
system("pause");
return 0;
}
1 2 3 4 5 6 7 8 9 10
请按任意键继续. . .
性能分析:无论如何,T=Θ(N^2)。如何快速找到最小元呢,针对N个位置的遍历无法加速,我们唯一能加速的就是通过scanForMin找到MinPosition的过程,每次找最小的元素,很容易联想到堆数据结构。利用小顶堆每个找到最小元素,获取最小元素O(1)时间复杂度,调整堆O(logn)时间复杂度,所以时间复杂度变为O(Nlog N)。不过建队需要额外O(N)空间,并且复制元素需要时间。
- 时间复杂度:O(n^2)
- 稳定性:不稳定
堆排序:利用堆数据结构加快scanForMin过程从而降低时间复杂度。
算法1:建立小顶堆,每次从堆顶取出最小元素。
#include<bits/stdc++.h>
using namespace std;
void percDown(vector<int>& arr,int p,int n) { //小顶堆的percDown操作,n:元素个数
int parent, child;
int x = arr[p];
for (parent = p; parent*2+1<n; parent=child) {
child = 2 * parent + 1;
if (child != n - 1 && arr[child] > arr[child + 1]) child++;
if (x < arr[child]) break;
else arr[parent] = arr[child];
}
arr[parent] = x;
}
void buildHeap(vector<int>& arr) { //建小顶堆
int n = arr.size();
for (int i = n / 2 - 1; i >= 0; i--) {
percDown(arr,i,n);
}
}
int deleteMin(vector<int>& arr,int n) {
int res = arr[0];
arr[0] = arr[n-1];
percDown(arr,0,n-1);
return res;
}
void heapSort1(vector<int>& arr) { //O(nlog n)
int n = arr.size();
buildHeap(arr); //O(n)
vector<int> tmp;
for (int i = 0; i < n; i++) { //O(n)
tmp.push_back(deleteMin(arr,n-i)); //O(log n)
}
for (int i = 0; i < n; i++) { //O(n)
arr[i] = tmp[i];
}
}
int main() {
vector<int> arr = { 8,6,10,7,9,4,3,2,5,1 };
heapSort1(arr);
for (auto x : arr) {
cout << x << " ";
}
cout << endl;
system("pause");
return 0;
}
1 2 3 4 5 6 7 8 9 10
请按任意键继续. . .
算法2:建立一个大顶堆,每次将对顶元素与当前需要调节的最后一个元素互换,这样最大元素调整到最终位置,现在只要对前面的元素调用percDown操作即可,以此类推...直到数组整体有序。
#include<bits/stdc++.h>
using namespace std;
void percDown(vector<int>& arr,int p,int n) { //大顶堆的percDown操作,n:元素个数
int parent, child;
int x = arr[p];
for (parent = p; parent*2+1<n; parent=child) {
child = 2 * parent + 1;
if (child != n - 1 && arr[child] < arr[child + 1]) child++;
if (x > arr[child]) break;
else arr[parent] = arr[child];
}
arr[parent] = x;
}
void buildHeap(vector<int>& arr) { //建大顶堆
int n = arr.size();
for (int i = n / 2 - 1; i >= 0; i--) {
percDown(arr,i,n);
}
}
void heapSort(vector<int>& arr) { //O(nlog n)
int n = arr.size();
buildHeap(arr); //O(n)
for (int i = n-1; i > 0; i--) {
swap(arr[0],arr[i]); //deleteMax操作
percDown(arr,0,i);
}
}
int main() {
vector<int> arr = { 8,6,10,7,9,4,3,2,5,1 };
heapSort(arr);
for (auto x : arr) {
cout << x << " ";
}
cout << endl;
system("pause");
return 0;
}
#include<bits/stdc++.h>
using namespace std;
//将n个元素的数组以arr[p]为根的子堆调整为最大堆
void percDown(vector<int>& arr,int p,int n) { //大顶堆的percDown操作,n:元素个数
int parent, child;
int x = arr[p];
for (parent = p; parent*2+1<n; parent=child) {
child = 2 * parent + 1;
if (child != n - 1 && arr[child] < arr[child + 1]) child++; //child指向左右子节点的较大者
if (x > arr[child]) break; //已经在合适位置,直接break
else arr[parent] = arr[child]; //下滤
}
arr[parent] = x;
}
void heapSort(vector<int>& arr) { //O(nlog n)
int n = arr.size();
for (int i = n / 2 - 1; i >= 0; i--) { //建大顶堆
percDown(arr, i, n);
}
for (int i = n-1; i > 0; i--) {
swap(arr[0],arr[i]); //deleteMax操作
percDown(arr,0,i);
}
}
int main() {
vector<int> arr = { 8,6,10,7,9,4,3,2,5,1 };
heapSort(arr);
for (auto x : arr) {
cout << x << " ";
}
cout << endl;
system("pause");
return 0;
}
性能分析:建堆是从第一个非叶子结点开始的,不断调用percDown操作,大堆和小堆的percDown操作结构一致,只是内部小于大于号判断有所变化。算法2原地操作,O(1)额外空间开销,时间复杂度也能达到O(nlog n)。(perc:percolate)
- 定理:堆排序处理N个不同元素的随机排列的平均比较次数是2NlogN-O(Nlog logN)。
- 虽然堆排序给出最佳平均时间复杂度,但实际效果不如用Sedgewick增量序列的希尔排序。
- 稳定性:不稳定
来源:CSDN
作者:cainiao_23333
链接:https://blog.csdn.net/weixin_41876385/article/details/103606084