排序分为内部排序和外部排序,内部排序是指待排序的数据都是在内存中的,例如数组;外部排序指待排序资源在内存外,例如对文件的排序。此篇说的是内部排序。通俗地来说,内部排序就是将一堆数据按一定规则对它进行排序。排序又分为稳定排序和不稳定的排序,如果初始序列Ai,Ak有序(Ai = Ak),排序后变成了Ak,Ai,称为不稳定排序。下面介绍几个经典常见的排序。(以下排序都是以数组为例进行排序)
1.选择排序
思路就是每次从待排序列取出最大或最小的值的元素,插入到以有序的序列后边。
void select_sort(int A[], int n){
cout << "select sort" << endl;
int min, k;
for(int i = 0; i < n - 1; i++){
min = A[k = i];
for(int j = i + 1; j < n; j++)
if(min > A[j])
min = A[k = j];
A[k] = A[i];
A[i] = min;
}
}
2.直接插入排序
从待排序列中遍历元素(不需要做对比,直接从取第一个元素即可),将选中元素按顺序插入到以排序的序列中。
void insert_sort(int A[], int n){
cout << "insert sort" << endl;
int tmp, j;
for(int i = 1; i < n; i++){
tmp = A[i];
if(A[i] < A[i-1]){
j = i;
while(j > 0 && A[j - 1] > tmp){
A[j] = A[j - 1];
j--;
}
A[j] = tmp;
}
}
}
3.冒泡排序
简单的说就是前后两个元素依次比较,如果不符合,就交换两者。每一趟排序,可以排出一个最大或最小的元素,依次冒泡就可以做出排序。通常需要n-1趟排序,可以优化一下,用一个标记变量来检测,如果一趟排序中没有元素进行过交换,说明当前序列已经有序了,不需要在交换了。
void bubble_sort(int A[], int n){
bool check;
int tmp;
for(int i = 0; i < n; i++){
check = true;
for(int j = 0; j < n - 1 - i; j++){
if(A[j] > A[j + 1]){
tmp = A[j];
A[j] = A[j + 1];
A[j + 1] = tmp;
check = false;
}
}
if(check)
break;
}
}
4.希尔排序
希尔排序是将待排序列按照某一个增量分为若干个子序列,依次对子序列进行插入排序,让待排序列部分有序,然后将增量递分为更多的子序列,在做上述排序,直到增量为1.增量的选择是依次递减的,增量选择的好坏关系到时间复杂度,此处选择折半递减。下面看图文讲解。
void shell_insert(int A[], int d, int n){
int tmp, j;
for(int i = d; i < n; i++){
tmp = A[i];
j = i - d;
while(j >= 0 && A[j] > tmp){
A[j + d] = A[j];
j -= d;
}
if(j != i - d)
A[j + d] = tmp;
}
}
void shell_sort(int A[], int n){
int d = n / 2;
while(d >= 1){
shell_insert(A, d, n);
d /= 2;
}
}
5.归并排序
思路是将待排序列,例如有n个记录,可以将它们看成是n个有序的子序列,对其两两进行排序,然后合并成n/2个有序的子序列,再依次两两合并,直到最后剩下一个有序序列,排序完成。
void Merge(int A[], int B[], int s, int m, int t){
int i,j,k;
for(i = m + 1, j = s; s <= m && i <= t; j++){
if(A[s] < A[i])
B[j] = A[s++];
else
B[j] = A[i++];
}
if(s <= m){
for(k = 0; k <= m - s; k++)
B[j + k] = A[s + k];
}
if(i <= t)
for(k = 0; k <= t - i; k++)
B[j + k] = A[i + k];
}
void MSort(int A[], int B[], int s, int e){
int m;
int tmp[100];
if(s == e)
B[s] = A[s];
else{
m = (s + e) / 2;
MSort(A, tmp, s, m);
MSort(A, tmp, m + 1, e);
Merge(tmp, B, s, m, e);
}
}
各种排序比较
序号 | 排序类别 | 时间复杂度 | 空间复杂度 | 稳定 |
1 | 插入排序 | O(n2) | 1 | √ |
2 | 希尔排序 | O(n2) | 1 | × |
3 | 冒泡排序 | O(n2) | 1 | √ |
4 | 选择排序 | O(n2) | 1 | × |
5 | 快速排序 | O(Nlogn) | O(logn) | × |
6 | 堆排序 | O(Nlogn) | 1 | × |
7 | 归并排序 | O(Nlogn) | O(n) | √ |