交换排序
交换,是指根据序列中两个元素关键字的比较结果来对换这两个记录在序列中的位置。
冒泡排序 |
基本思想是从后往前(或从前往后)两两比较相邻元素的值,若为逆序(即A[i-1]>A[i]),则交换它们,直到序列比较完。
实现图示:
核心代码:
void swap(int &a,int &b){
int c;
c = a;
a = b;
b = c;
}
void BubbleSort(int A[],int n){
int i,j;bool flag;
for(i=0;i<n-1;i++){
flag = false; //表示本趟冒泡是否发生交换的标志
for(j=n-1;j>i;j--){ //一趟冒泡过程
if(A[j-1]>A[j]){ //若为逆序
swap(A[j-1],A[j]); //交换
flag = true;
}
}
if(flag=false){
return;
}
}
}
性能分析:
空间效率 | O(1) |
时间效率 | O(n^2) |
稳定性 | 稳定 |
适用性 | 适用于顺序存储和链式存储的线性表 |
在最好情况下,元素已经有序,比较次数为n-1次,移动次数为0,此时时间复杂度为O(n)
在最坏情况下,元素为逆序,总比较次数达到最大,为
∑
i
=
1
n
−
1
n
(
n
−
1
)
/
2
\sum_{i=1}^{n-1} n(n-1)/2
i=1∑n−1n(n−1)/2
总的移动次数也达到最大,为
∑
i
=
1
n
−
1
3
n
(
n
−
1
)
/
2
\sum_{i=1}^{n-1} 3n(n-1)/2
i=1∑n−13n(n−1)/2
tips:每次比较后移动元素三次来交换元素位置。
快速排序 |
基本思想是基于分治法
实现图示:
核心代码:
int Partition(int A[],int low,int high){ //一趟划分
int pivot = A[low]; //将当前表中第一个元素设为枢轴,对表进行划分
while(low<high){
while(low<high && A[high]>=pivot){
high--;
}
A[low] = A[high]; //将比枢轴小的元素移动到左端
while(low<high && A[low]<=pivot){
low++;
}
A[high] = A[low]; //将比枢轴大的元素移动到右端
}
A[low] = pivot; //将枢轴元素存放到最终位置,此时low=high
return low; //返回存放枢轴的最终位置
}
void QuickSort(int A[],int low,int high){
if(low < high){
int pivotpos = Partition(A,low,high);
QuickSort(A,low,pivotpos-1); //依次对两个子表进行递归排序
QuickSort(A,pivotpos+1,high);
}
}
性能分析:
空间效率 | O(log_2 n) |
时间效率 | O(nlog_2 n) |
稳定性 | 不稳定 |
适用性 | 适用于顺序存储和链式存储 |
空间效率:由于快速排序是递归的,需要一个递归工作栈来保存每层递归调用的必要信息,其容量应与递归调用的最大深度一致。
时间效率:运行时间与划分是否对称有关,快速排序的最坏情况发生在两个区域分别包含n-1个元素和0个元素时。
快速排序是所有内部排序算法中平均性能最优的排序算法。
tips:并不产生有序子序列,但每趟排序后会将枢轴元素放到其最终的位置上。