1.交换排序
1.1 基本思想
- 两两比较,如果发生逆序则交换,知道所有记录都排好序为止。
1.2 常见的交换排序
- 冒泡排序
- 快速排序
2.冒泡排序
2.1 基本思想
- 每趟不断将记录两两比较,并按“前小后大”规则交换
2.2 冒泡排序排序过程(升序)
- 初始:21、25、49、25*、16、8 n=6
- ·······
- 第二趟排序:
- 排序后结果:21、25、16、8 、25* 、49 n=6
- 第一趟排序:
- 第一次排序:判断 21、25是否逆序,不是 则21、25、49、25*、16、8 n=6
- 第二次排序:判断 25、49是否逆序,不是 则21、25、49、25*、16、8 n=6
- 第三次排序:判断 49、25*是否逆序,是 则21、25、25*、49、16、8 n=6
- 第四次排序:判断 49、16是否逆序,是 则21、25、25*、16、49、8 n=6
- 第五次排序:判断 49、8是否逆序,是 则21、25、25*、16、8 、49 n=6
2.3 算法描述
void bubble_sort(Sqlist &L){
int m,i,j;RedType x;
for(m=1;m<=n-1;m++){
for(j=1;j<=n-m;j++){
if(L.r[j].key < L.r[j+1].key){
x=L.r[j];
L.r[j]=L.r[j+1];
L.r[j+1]=x;
}
}
}
}
public static void bubbleSort(int[] arr){
int n = arr.length-1;
for(int i=n;i>=0;--i){
for(int j=0;j<i;j++){
if(arr[j] >arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
2.4 特点
- 优点:每趟结束时,不仅能挤出一个最大值到后面,还能同时部分理顺其他元素;
- 如何提高效率?
- 一旦某一趟比较时不出现记录交换,说明已经排好序了,就可以结束本算法。
- 如何提高效率?
2.5 冒泡排序算法分析
- 时间复杂度
- 算法评价
- 最好情况下时间复杂度:O(n)
- 最坏情况下时间复杂度:O(n²)
- 平均时间复杂度:O(n²)
- 空间复杂度:O(1)
- 冒泡排序是稳定排序。
- 最好情况(正序)
- 比较次数:n-1
- 移动次数:0
- 最坏情况(逆序)
- 比较次数:(n-1)*n/2
- 移动次数:3(n-1)*n/2
- 算法评价
3.快速排序
3.1 基本思想
- 任取一个元素为中心(pivot)。
- 直到每个子表的元素只剩一个。
- 对各个子表重新选择中心元素并以此规则调整。
- 所有比它小的元素一律放前,比他大的元素一律放后,形成左右两个子表。
2.2 算法过程
- 每一趟的子表的形成都是采用从两头向中间交替式逼近法
- 由于每趟中对各字表的操作都相似,可采用递归算法。
2.3 算法描述
public static void quickSort(int[] arr){
if(arr.length>0){
uickSort(arr,0,arr.length-1);
}
}
private static void uickSort(int[] arr,int low,int high){
int pivot,i,j;
if(low>=high){
return;
}
pivot = arr[low];
i=low;
j=high;
while(i<j){
while(arr[j] >= pivot && i<j){
j--;
}
while(arr[i] <= pivot && i<j){
i++;
}
if(i<j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
arr[low] = arr[i];
arr[i] = pivot;
uickSort(arr,low,i-1);
uickSort(arr,i+1,high);
}
void main(){
QSort(L,1,L.length);
}
void QSort(Sqlist &L,int low,int high){ //对顺序表L进行快速排序
if(low<high){ //长度大于1
povitloc = Partition(L,low,high); //将L一分为二,povitloc为数轴元素排好序的位置
QSort(L,low,povitloc-1); //对低位子表排序
QSort(L,povitloc+1,high); //对高位子表排序
}
}
int Partition(Sqlist &L,int low,int high){
L.r[0] = L.r[low];povitkey = L.r[low].key;
while(low<high){
while(low<high && L.r[high].key >= povitkey)high--;
L.r[low]=L.r[high];
while(low<high && L.r[low].key <= povitkey)low++;
L.r[high]=L.r[low];
}
L.r[low] = L.r[0];
return low
}
2.4 快速排序算法分析
- 时间复杂度
- 自然性
- 快速排序不适于对原本有序或者基本有序的记录序列进行排序。
- 稳定性
- 快速排序是一种不稳定的排序方法。
- 例如:49,38,49*,20,97,76
- 进行一次排序后结果为:20,38,49*,49,97,76
- 快速排序是一种不稳定的排序方法。
- 空间复杂度
- 快速排序不是原地排序
- 由于程序中使用了递归,需要递归调用栈的支持,而栈的长度取决于递归调用的深度。
- 平均情况下:O(log(n))
- 最坏情况下:O(n);
- 可以证明,平均计算时间是O(nlog2(n))。
- Qsort():O(log2(n));
- Partition():O(n);
- 实验结果表明,就平均计算时间而言,快速排序时我们所讨论的所有内排序方法最好的一个
- 自然性
- 快速排序效率影响分析
- 划分元素的选取是影响时间性能的关键
- 输入的次序越乱,所选划分元素值的随机性越好,排序速度越快,快速排序不是自然性排序