定义:
1.稳定性:相等的数排序前和排序后的相对顺序相同,即是稳定性。
2.稳定排序和非稳定排序:存在某个例子使算法失去稳定性,即为非稳定排序
排序分类:
A.插入排序(新建一个数列作为有序列表,在原数列中取数进行插入,保证新列表的有序性)
直接插入(稳定):在插入第i元素时,前i-1个已经排好序,只要直接插入到正确位置就好。...O(n^2)
-但是其实在输入的时候就进行插入会很好用,虽然我没用过..不过我是这么想的。
void dir_insert(int A[],int N){
int j,temp;
for(int i=1;i<N;i++){//i要从1开始
temp = A[i];//插入A[i]
j=i-1;//倒序
while(A[j]>temp && j>=0){
A[j+1] = A[j];//后挪
j--;
}
A[j+1] = temp;//插入的位置是j+1
}
};
希尔(shell)排序(不稳定):即分组插入,直接插入的改进版,将文件记录分成d1组,所有在d1的倍数上的数先取出来做一次直接插入,然后去d2....直到dn=1。(可能消除多个元素交换)---除2 && 确保di为基数
void shell_sort(int A[],int N){
int i,j,k,temp;
(N/2)%2 ==0 ? k=N/2 +1 : k=N/2;//确保奇数
while(k>0){
for(i=k;i<N;i+=k){//过程与直接插入基本类似
temp = A[i];
j = i-k;
while(A[j]>temp && j>=0){
A[j+k] = A[j];
j-=k;
}
A[j+k] = temp;
}
if(k == 1) break;
(k/2)%2 == 0 ? k=k/2+1 : k=k/2;
}
};
B.选择排序
直接选择排序(不稳定):选出最小元素,放在第一位,然后在余下元素中选择最小元素....
堆排序(不稳定):新建一个列表做有序列表,从原数组中找出最大元素,放在列表末端,然后在原数组中删除,在余下数组中找寻最大元素.....直到所有数全部排到有序列表中。--heap i的左儿子在2i,右儿子在2i+1,左右儿子大于父亲
这两个算法没有实现,一个是太简单,一个太复杂..............
D.交换排序
冒泡排序(稳定):将所有待排序的数放入工作列表中,从第一个数到倒数第二个数,逐个检查,如果比后面的数大就进行交换,不断重复...从第一个数到倒数第二个数的检查和交换,直到不能再交换则排序完成。
void bubble_sort(int A[],int N){
int i;
bool flag = true;
while(flag){
flag = false;
for(i=0;i<N-1;i++){
if(A[i]>A[i+1]){
int b=A[i+1];
A[i+1]=A[i];
A[i]=b;
flag = true;
}
}
}
};
快速排序(不稳定):将数组分份,前半部的数都小于后半部的数。从数中取一个值做主元,大于主元的放右边,小于主元的放左边。左右两边继续重复递归。
void quick_sort(int A[],int low,int high){//from low to high..0~N-1......写了很久没能解决数组的理解问题,用挖坑法最容易实现
if(low<high){
int temp = A[low];//相当于在A[low]处挖出一个坑..后面回填
int l=low;
int h= high;
while(l<h){
while(A[h]>=temp && h>l) h--;
A[l] = A[h];//往A[l]处填坑,新挖出一个坑在A[h]
while(A[l]<temp && h>l) l++;
A[h]=A[l];//往A[h]处填坑,新挖出一个在A[l]
}
A[l] = temp;//回填最后剩下的A[l]的坑..正好是temp的位置
quick_sort(A,low,l-1);
quick_sort(A,l+1,high);
}
return;
};
D.归并排序:将n个数看成n张有序表,两两进行合并,得到n/2张长度为2的有序表...直到最后合并至1张长度为n的有序表。
时间复杂度:
选择排序:O(N^2)
插入排序:O(N^2)
冒泡排序:O(N^2)
堆排序:O(N logN)
归并排序:O(N logN)
快速排序:最理想..O(N logN) 最坏..O(N^2)--因为退化
希尔排序:平均时间O(N logN) 最坏O(N^s)--1< s <2