-
冒泡排序:每循环一次,对比前后两个数据,把大的挪到前面,所以循环一次最后一个是最大的元素,下次循环可以少循环一位
void Bubble_sort(vector<int>& vect) { int size = vect.size(); int N = size; int move_num = 0; int tem; for (int k = 0; k < size; k++) { N = size - k; // n,n-1,...,2,1 move_num = 0; for (int i = 0; i < N-1; i++) //注意是N-1 { if (vect[i] > vect[i + 1]) { tem = vect[i]; vect[i] = vect[i + 1]; vect[i + 1] = tem; move_num++; } } if(move_num==0) //针对冒泡排序的优化,如果这次没有移动,说明已经排好了,break出去 break; } }
-
选择排序:从头到尾扫描,找到最小的元素,和最前面的元素互换,下次从第二个开始
所以理论上选择排序,遍历的次数多,但是最多交换n次,不像冒泡,可能要交换移动很多次
void select_sort(vector<int>& vect) { int size = vect.size(); if(size<2) return; int N=size; for(int i=0;i<size;i++) { N=size-i; //n,n-1,...1 int max_id = N-1; for(int j=0;j<N-1;j++) { if(vect[j]>vect[max_id]) { max_id = j; //最大的index } } //交换最大的和范围内最后一个 int tem = vect[max_id]; vect[max_id] = vect[N-1]; vect[N-1]=tem; } }
-
插入排序:从第二个数开始,一直往前面对比,比他大,就后挪一个,直到不比它大,放到这,break出去。纸牌比喻
void insert_sort(vector<int>& vect) { int size=vect.size(); if(size<2) return; int tem = 0; for(int N=1;N<size;N++) //1,2,...,n-1 { tem = vect[N]; int j=N-1; for(;j>=0;j--) { if(vect[j]>tem) { vect[j+1]=vect[j];//后移一位 } else { break; } } vect[j+1]=tem; } }
-
希尔排序:相当于改进的插入排序,每间隔gap个分成一组进行插入排序,gap逐渐减小到1
void shell_sort(vector<int>& vect) { int size=vect.size(); if(size<2) return; for(int gap=size/2; gap>0; gap=gap/2) { //会有gap组,首个元素的索引分别是0,1,2,gap-1 for(int start=0;start<gap;start++) //首个元素的索引 { int N=1; //插入排序,从第二个开始 while(start+N*gap<size) { int tem=vect[start+N*gap]; //要插入排序的最后一个元素 int j=N-1; //前一个开始 for(;j>=0;j--) { if(vect[start+j*gap]>tem) { vect[start+(j+1)*gap]=vect[start+j*gap];//后挪 } else { break; } } vect[start+(j+1)*gap]=tem; //如果全部后移,j=-1; 否则就是j就是第一个比它小的 N++; } } } }
-
快速排序:每次取出一个元素,代码里是每次取出范围内第一个元素,把小于它的元素都放到左边,大于它的都放到右边,也就分割成了两部分,再对这两部分进行同样操作,所以可以用迭代实现,当左索引不小于右索引,停止迭代
void fast_sort(vector<int>& vect, int L, int R) { if(L>=R) return; int left=L; int right=R; int elem = vect[left]; //取出最左边元素 int LR=0; //0表示空位在左边,1表示空位在右边 while(left<right) { if(LR==0) //空位在左边 { if(vect[right]<elem) { vect[left]=vect[right]; //把右边小的放到空位 left++; //left标记向右移动一位 LR=1;//空位变成了右边 continue; } else { right--; continue; } } if(LR==1) //空位在右边 { if(vect[left]>elem) { vect[right]=vect[left]; right--; LR=0; //空位变成了左边 continue; } else { left++; continue; } } } //此时已经left=right是空位了 vect[left]=elem; //[L,left-1],left,[left+1,R]分成了两边的区间,左边的都小,右边的都大 fast_sort(vect,L,left-1); fast_sort(vect,left+1,R); }
-
归并排序:两个排好序的数组合并成一个有序的数组,递归地把数组分成单个元素,再两两合并
void Merge(vector<int> &VEC, int low, int mid, int high) { int start1 = low; //[low,mid] int start2 = mid + 1; //[mid+1, high] //存储临时排好序的 vector<int> tem(high - low + 1, 0); int k = 0; while (start1 <= mid && start2 <= high) { if (VEC[start1] <= VEC[start2]) { tem[k++] = VEC[start1++]; } else { tem[k++] = VEC[start2++]; } } //前半段还有剩余 while (start1 <= mid) { tem[k++] = VEC[start1++]; } //或者后半段还有剩余 while (start2 <= high) { tem[k++] = VEC[start2++]; } //把临时排好序的,插入原来序列 k = 0; for (int i = low; i < high; i++, k++) { VEC[i] = tem[k]; } } //归并排序 void MergeSort(vector<int> &VEC, int low, int high) { // 终止递归的条件,子序列长度为1 if (low >= high) { return; } //先分,一直分到长度为1 int mid = low + (high - low) / 2; // 取得序列中间的元素 MergeSort(VEC, low, mid); // 对左半边递归 MergeSort(VEC, mid + 1, high); // 对右半边递归 //合并,把[low,mid] [mid+1, high]合并到一起 Merge(VEC, low, mid, high); }
7.堆排序
#include<queue> void heap_sort(vector<int> &vect) { priority_queue<int, vector<int>, greater<int>> min_heap; //最小堆 for (int i = 0; i < vect.size(); i++) { min_heap.emplace(vect[i]); } for (int i = 0; i < vect.size(); i++) { vect[i] = min_heap.top(); min_heap.pop(); } }
对比七种排序算法的时间效率
冒泡、选择、插入、希尔,快速, 归并, 堆排序, 越来越快
#include <iostream>
#include <vector>
#include <chrono>
#include <queue>
using namespace std;
//冒泡排序
void bubble_sort(vector<int> &vect);
//选择排序
void select_sort(vector<int> &vect);
//插入排序
void insert_sort(vector<int> &vect);
//希尔排序
void shell_sort(vector<int> &vect);
//快速排序
void fast_sort(vector<int> &vect, int L, int R);
//归并排序
void merge_sort(vector<int> &vect, int L, int R);
void merge(vector<int> &vect, int left, int mid, int right);
//堆排序
void heap_sort(vector<int> &vect);
int main()
{
const int N = 100000;
vector<int> VEC(N, 0);
srand(time(0));
for (int i = 0; i < N; i++)
{
VEC[i] = rand() % (N + 1);
}
vector<int> VEC1 = VEC;
vector<int> VEC2 = VEC;
vector<int> VEC3 = VEC;
vector<int> VEC4 = VEC;
vector<int> VEC5 = VEC;
vector<int> VEC6 = VEC;
//冒泡排序
chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
bubble_sort(VEC1);
chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
cout << "冒泡排序: " << time_used.count() << " s" << endl;
for (int i = 0; i < 30; i++)
cout << VEC1[i] << " ";
cout << endl;
//选择排序
t1 = chrono::steady_clock::now();
select_sort(VEC2);
t2 = chrono::steady_clock::now();
time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
cout << "选择排序: " << time_used.count() << " s" << endl;
for (int i = 0; i < 30; i++)
cout << VEC2[i] << " ";
cout << endl;
//插入排序
t1 = chrono::steady_clock::now();
insert_sort(VEC3);
t2 = chrono::steady_clock::now();
time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
cout << "插入排序: " << time_used.count() << " s" << endl;
for (int i = 0; i < 30; i++)
cout << VEC3[i] << " ";
cout << endl;
//希尔排序
t1 = chrono::steady_clock::now();
shell_sort(VEC4);
t2 = chrono::steady_clock::now();
time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
cout << "希尔排序: " << time_used.count() << " s" << endl;
for (int i = 0; i < 30; i++)
cout << VEC4[i] << " ";
cout << endl;
//快速排序
t1 = chrono::steady_clock::now();
fast_sort(VEC, 0, N - 1);
t2 = chrono::steady_clock::now();
time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
cout << "快速排序: " << time_used.count() << " s" << endl;
for (int i = 0; i < 30; i++)
cout << VEC[i] << " ";
cout << endl;
//归并排序
t1 = chrono::steady_clock::now();
merge_sort(VEC5, 0, N - 1);
t2 = chrono::steady_clock::now();
time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
cout << "归并排序: " << time_used.count() << " s" << endl;
for (int i = 0; i < 30; i++)
cout << VEC5[i] << " ";
cout << endl;
//堆排序
t1 = chrono::steady_clock::now();
heap_sort(VEC6);
t2 = chrono::steady_clock::now();
time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
cout << "堆排序: " << time_used.count() << " s" << endl;
for (int i = 0; i < 30; i++)
cout << VEC6[i] << " ";
cout << endl;
return 0;
}
void bubble_sort(vector<int> &vect)
{
int size = vect.size();
int N = size;
int move_num = 0;
int tem;
for (int k = 0; k < size; k++)
{
N = size - k; // n,n-1,...,2,1
move_num = 0;
for (int i = 0; i < N - 1; i++) //注意是N-1
{
if (vect[i] > vect[i + 1])
{
tem = vect[i];
vect[i] = vect[i + 1];
vect[i + 1] = tem;
move_num++;
}
}
if (move_num == 0) //针对冒泡排序的优化,如果这次没有移动,说明已经排好了,break出去
break;
}
}
void select_sort(vector<int> &vect)
{
int size = vect.size();
if (size < 2)
return;
int N = size;
for (int i = 0; i < size; i++)
{
N = size - i; // n,n-1,...1
int max_id = N - 1;
for (int j = 0; j < N - 1; j++)
{
if (vect[j] > vect[max_id])
{
max_id = j;
}
}
int tem = vect[max_id];
vect[max_id] = vect[N - 1];
vect[N - 1] = tem;
}
}
void insert_sort(vector<int> &vect)
{
int size = vect.size();
if (size < 2)
return;
int tem = 0;
for (int N = 1; N < size; N++) // 1,2,...,n-1
{
tem = vect[N];
int j = N - 1;
for (; j >= 0; j--)
{
if (vect[j] > tem)
{
vect[j + 1] = vect[j]; //后移一位
}
else
{
break;
}
}
vect[j + 1] = tem;
}
}
void shell_sort(vector<int> &vect)
{
int size = vect.size();
if (size < 2)
return;
for (int gap = size / 2; gap > 0; gap = gap / 2)
{
//会有gap组,首个元素的索引分别是0,1,2,gap-1
for (int start = 0; start < gap; start++) //首个元素的索引
{
int N = 1; //插入排序,从第二个开始
while (start + N * gap < size)
{
int tem = vect[start + N * gap]; //要插入排序的最后一个元素
int j = N - 1; //前一个开始
for (; j >= 0; j--)
{
if (vect[start + j * gap] > tem)
{
vect[start + (j + 1) * gap] = vect[start + j * gap]; //后挪
}
else
{
break;
}
}
vect[start + (j + 1) * gap] = tem; //如果全部后移,j=-1; 否则就是j就是第一个比它小的
N++;
}
}
}
}
void fast_sort(vector<int> &vect, int L, int R)
{
if (L >= R)
return;
int left = L;
int right = R;
int elem = vect[left];
int LR = 0; // 0表示空位在左边,1表示空位在右边
while (left < right)
{
if (LR == 0)
{
if (vect[right] < elem)
{
vect[left] = vect[right]; //把右边小的放到空位
left++; // left标记向右移动一位
LR = 1; //空位变成了右边
continue;
}
else
{
right--;
continue;
}
}
if (LR == 1) //空位在右边
{
if (vect[left] > elem)
{
vect[right] = vect[left];
right--;
LR = 0;
continue;
}
else
{
left++;
continue;
}
}
}
//此时已经left=right是空位了
vect[left] = elem;
fast_sort(vect, L, left - 1);
fast_sort(vect, left + 1, R);
}
void merge_sort(vector<int> &vect, int L, int R)
{
if (L >= R)
return;
int mid = L + (R - L) / 2;
//先把左右两边的排好序,再合并
merge_sort(vect, L, mid);
merge_sort(vect, mid + 1, R);
merge(vect, L, mid, R);
}
void merge(vector<int> &vect, int left, int mid, int right)
{
int id1 = left;
int id2 = mid + 1;
int k=0;
vector<int> tem(right - left + 1, 0);
while(id1<=mid && id2<=right)
{
if(vect[id1]<vect[id2])
{
tem[k]=vect[id1];
id1++;
k++;
}
else
{
tem[k]=vect[id2];
id2++;
k++;
}
}
while(id1<=mid)
{
tem[k]=vect[id1];
id1++; k++;
}
while(id2<=right)
{
tem[k]=vect[id2];
id2++; k++;
}
k=0;
for(;k<right-left+1;k++)
{
vect[left+k]=tem[k];
}
}
void heap_sort(vector<int> &vect)
{
priority_queue<int, vector<int>, greater<int>> min_heap;
for (int i = 0; i < vect.size(); i++)
{
min_heap.emplace(vect[i]);
}
for (int i = 0; i < vect.size(); i++)
{
vect[i] = min_heap.top();
min_heap.pop();
}
}
结果
冒泡排序: 15.8883 s
0 0 1 4 4 4 5 9 10 10 11 11 13 13 13 15 15 16 18 18 19 20 20 21 23 23 24 26 27 27
选择排序: 3.63016 s
0 0 1 4 4 4 5 9 10 10 11 11 13 13 13 15 15 16 18 18 19 20 20 21 23 23 24 26 27 27
插入排序: 1.20537 s
0 0 1 4 4 4 5 9 10 10 11 11 13 13 13 15 15 16 18 18 19 20 20 21 23 23 24 26 27 27
希尔排序: 0.0167228 s
0 0 1 4 4 4 5 9 10 10 11 11 13 13 13 15 15 16 18 18 19 20 20 21 23 23 24 26 27 27
快速排序: 0.00830173 s
0 0 1 4 4 4 5 9 10 10 11 11 13 13 13 15 15 16 18 18 19 20 20 21 23 23 24 26 27 27
归并排序: 0.0135148 s
0 0 1 4 4 4 5 9 10 10 11 11 13 13 13 15 15 16 18 18 19 20 20 21 23 23 24 26 27 27
堆排序: 0.012091 s
0 0 1 4 4 4 5 9 10 10 11 11 13 13 13 15 15 16 18 18 19 20 20 21 23 23 24 26 27 27
所以冒泡,选择,插入 越来越快,但是都比较慢
希尔,归并,堆排序,快速的效率越来越高. 快速最快
个人感觉快速排序(最快)的迭代代码可能比希尔还要好写一些
归并排序也很快,但是仍然没有快速排序快