排序算法可以分为内部排序和外部排序。
内部排序是数据记录在内存中进行排序。
而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。
常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。
用一张图概括:
1.冒泡排序
思想:从后往前将数组中的元素两两比较,交换两者的位置取小的那一个元素,直到数组开头。重复这一过程,直到最后两个元素比较之后交换位置
(1)平均时间复杂度O(n2),是稳定排序
(2)最坏时间复杂度O(n2),逆序的时候
(3)最好时间复杂度O(n),顺序的时候
void bubble_sort(vector<int> &array)
{
int n = array.size();
for(int i = 1; i <= n-1; i++)
{
bool flag = false;
for(int j = 0; j < n - i; j++)
{
if(array[j] > array[j+1])
{
flag = true;
swap(array[j], array[j+1]);
}
}
if(!flag)
break;
}
}

2.插入排序
从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置
(1)平均时间复杂度O(n2),稳定排序
(2)逆序情况每次循环都要比较n次,时间复杂度O(n)
(3)最好情况顺序,时间复杂度O(n)
void insert_sort(vector<int> &array)
{
int n = array.size();
for(int i = 1; i <= n-1; i++)
{
int temp = array[i];
int j;
for(j = i-1; j >= 0; j--)
{
if(temp < array[j])
{
array[j+1] = array[j];
}
else
{
array[j+1] = temp;
break;
}
}
}
}

3.希尔排序(改进简单插入排序,每次交换相隔一定距离的元素),希尔排序是不稳定排序
void shellsort(int A[],int N,int incre[],int M)
{
int i,j,k,l,increment,temp;
for(i=0;i<M;i++)
{
increment=incre[i];
for(j=increment;j<N;j=j++)
{
temp=A[j];
for(k=j;k-increment>=0;k=k-increment)
{
if(temp>=A[k-increment])
break;
else
A[k]=A[k-increment];
}
A[k]=temp;
}
printf("第%d次排序:",i);
for(l=0;l<N;l++)
printf("%d ",A[l]);
printf("\n");
}
}
4.选择排序
从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾
(1)平均时间复杂度O(n2),不稳定排序
(2)最坏和最好情况都是O(n2),因为每个循环都要比较n次
void select_sort(vector<int> &array)
{
int n = array.size();
for(int i = 0; i < n-1; i++)
{
int min = i;
for(int j = i+1; j < n; j++)
{
if(array[j] < array[min])
min = j;
}
if(min != i)
swap(array[min], array[i]);
}
}
5.堆排序
-
创建一个堆 H[0……n-1];
-
把堆首(最大值)和堆尾互换,调整剩余的堆,使堆首值最大。
-
重复此步骤,直至堆的大小变为1
(1)堆排序是不稳定排序
(2)最好和最坏时间复杂度都是O(nlogn)
void adjust(vector<int> &num, int p, int N)
{
/* 将N个元素的数组中以num[p]为根的子堆调整为最大堆 */
int temp = num[p];
int parent, child;
for(parent = p;(2*parent+1) < N; parent = child)
{
child = 2*parent +1;
if( (child+1 < N ) && (num[child]<num[child+1]))
child++;
if(temp >= num[child])
break;
else
num[parent] = num[child];
}
num[parent] = temp;
}
void heap_sort(vector<int> &array)
{
int n = array.size();
for(int i = n/2-1; i >= 0; i--)//将数组调整为最大堆
adjust(array, i, n);
for(int i = n-1; i > 0; i--)
{
swap(array[i], array[0]);/* 删除最大堆顶 */
adjust(array, 0, i);//调整堆
}
}
6.归并排序
(1)是稳定排序
(2)最坏和最好时候的时间复杂度都是O(nlogn)
#include<iostream>
#include<vector>
using namespace std;
void merge(vector<int> &array, int L, int R, int RightEnd)
{
int num = RightEnd-L+1;
int LeftEnd = R-1;
vector<int> temp(num);
int i = 0;
while(L <= LeftEnd && R <= RightEnd)
{
if(array[L] < array[R])
temp[i++] = array[L++];
else
temp[i++] = array[R++];
}
while(L <= LeftEnd)
temp[i++] = array[L++];
while(R <= RightEnd)
temp[i++] = array[R++];
for(int i = num-1; i >= 0; i--)
array[RightEnd--] = temp[i];
}
void merge_sort(vector<int> &array, int start, int end)
{
if(start < end)
{
int mid = (start + end)/2;
merge_sort(array, start, mid);
merge_sort(array, mid+1, end);
merge(array, start, mid+1, end);
}
}
int main()
{
int n;
cin>>n;
vector<int> array(n);
for(int i = 0; i < n; i++)
cin>>array[i];
merge_sort(array, 0, n-1);
for(int i = 0; i < n; i++)
cout<<array[i]<<endl;
return 0;
}



7.快速排序
-
从数列中挑出一个元素,称为 “基准”(pivot);
-
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
-
递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序
(1)不是稳定排序
(2)最好时间复杂度O(nlogn),最坏时间复杂度O(n2),最坏情况是每次基准都是最小或者最大的数,没有分成两个子序列
#include<iostream>
#include<vector>
using namespace std;
int partition(vector<int> &array, int low, int high)
{
int pivot = array[low];
while(low < high)
{
while(high > low && array[high] >= pivot)
high--;
array[low] = array[high];
while(low < high && array[low] < pivot)
low++;
array[high] = array[low];
}
array[low] = pivot;
return low;
}
void quick_sort(vector<int> &array, int start, int end)
{
if(start < end)
{
int index = partition(array, start, end);
quick_sort(array, start, index);
quick_sort(array, index+1, end);
}
}
int main()
{
int n;
cin>>n;
vector<int> array(n);
for(int i = 0; i < n; i++)
cin>>array[i];
quick_sort(array, 0, n-1);
for(int i = 0; i < n; i++)
cout<<array[i]<<endl;
return 0;
}