冒泡排序
思想:两两交换比较相邻的关键字,如果反序则交换,直到没有反序的记录为止。
//顺序表为L
void BubbleSort(sqlist *L){
int flag = TRUE;
for(int i=1; i<l->length && flag; ++i){
flag = FALSE:
for(int j= l->length; j>=i; j--){
if(l->r[j] > r[j+1]){
swap(l,j,j+1);
flag = TRUE;
}
}
}
}
复杂度分析:时间复杂度
- 最好比较n-1次
- 最坏逆序比较 n(n-1)/2
简单选择排序
思想:通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i(1<=i<=n)个记录交换
代码实现
void SelectSort(sqlist *L){
int min; //记录位置
for(int i=1; i<L->length; ++i){
min = i;
for(int j=i+1; j<=L->length; ++j){
if(l->r[min] > L->[j]){
min = j;
}
if(i != min)
swap(L,i,min);
}
}
}
查询次数:n(n-1)/2
时间复杂度: O(
n
2
n^{2}
n2)
快速排序
思想:通过一趟排序将待排序记录分割成独立的两部分,其中一部分的关键字均比另一部分记录的关键字小,则可分别对这两部分记录进行排序,以达到整个序列有序的目的。
代码实现
void QSort(Sqlist *L, int low, int hight){
int pivot;
if(low < high){
pivot = Partition(L,low,high); //将序列一分为二,并排序
QSort(L,low,pivot-1); //对低子序列递归排序
QSort(L,pivot+1.high);//对高字表递归排序
}
}
int partition(Sqlist *L,int low, int high){
int pivotkey;
pivotkey = L->r[low]; //用字表的第一个记录作为枢纽记录
while(low < high){ //从表的两端交替想中间扫描
while(low<high && L->r[high]>=pivotkey)
high--;
swap(L,low,high); //将比枢纽记录小的交换到低位
while(low<high && L->r[low]<=pivotkey)
low++;
swap(L,low,high); //将比枢纽记录大的记录交换到高位
}
return low; //返回枢纽所在位置
}
-优化中间枢纽(pivotkey)的选取:如果枢纽选取太大或者太小都会影响排序的性能。一般是三数取中 取三个关键字先进行排序,将中间数作为枢纽。
int pivotkey;
int m = low+(high-low);
if(L->r[low] > L->r[high])
swap(L,low,high);
if(L->r[m] > L->r[high])
swap(L,low,high);
if(L->r[m] > L->r[low])
swap(L,low,high);
prvotkey = L->r[low];
对于大的数组说,可以采用九数取中,分别取三组三个数的组,每组取中,然后再从这三个数中取中作为枢纽pivotkey,
-优化递归操作:递归对于性能有一定的影响,QSort函数在其尾部有两次递归操作,如果带我排序的序列划分极端不平衡,递归深度将趋近于n,而不是平衡时的 log 2 n \log_2{n} log2n,这样不仅仅是速度慢的问题了。栈的大小是很有限的,每次递归调用都会耗费一定栈的空间,函数的参数越多,每次递归消耗的空间也越多。因此如果能减少递归,将会很大程度的提高性能。
改进代码
void QSort(Sqlist *L,int low, int high){
int pivot;
if((high-low) > MAX_LENGTH_INSERT_SORT){
while(low < high){
pivot = Parrtition(L,low,high);
QSort(L,low,pivot-1);
low = pivot+1;
}
}
else
Insertsort(L);
}
把if该成while后,第一次递归以后,变量low在下面用不到,可以将pivot+1赋值给low,再循环一次后,来一次Partition(L,low,high),其效果等同于QSort(L,pivot+1,high),结果相同,但因采用迭代而不是递归的方法可以缩减堆栈深度,从而提高了整体性能。