一、交换排序
(1)基本思想:两两比较待排序元素的关键字,发现次序相反则交换,直到没有反序元素为止。
(2)分类:冒泡排序、快速排序。
1.冒泡排序
(1)基本思想:通过无序区中相邻元素的两两比较和位置的交换,将最小的元素如气泡一样往前冒直至最前面。
(2)注意事项:有序区一定是全局有序,也就是说每趟产生的有序区所有位置都归位了。
(3)算法:
void BubbleSortl(Elemtype R[],int n)
{
int i,j;
bool exchange;
for(i=0;i<n-1;i++) //i<n-1的原因是0~n-2都有序,最后一个元素的位置已经确定不动了,i之前为有序区间
{
exchange=false; //用于判断剩余元素是否发生交换,若无则跳出节省时间
for(j=n-1;j>i;j--) //从后往前扫描
if(R[j].key<R[j-1].key)
{
swap(R[j].key,R[j-1].key); //交换两元素
exchange=true; //交换一次置为true
}
if(!exchange) //判断
return;
}
}
void swap(int &a,int &b)
{
int tmp=a;
a=b;
b=tmp;
}
(4)算法分析:
空间复杂度:O(1)
时间复杂度:O(n²)
稳定算法,顺序表链表都可以。
2.快速排序
(1)基本思想:在待排序的元素中任选一个元素作为基准,把该元素放在适当位置,数据序列被“划分”成两部分,前一部分是关键字更小的,后一部分是关键字更大的,重复此操作,直到所有数据序列都被划分。
(2)划分具体过程partition(R,low,high):
①选择基准并暂存在tmp中:为了方便一般选取序列最左的元素(tmp=R[low])
②low所指位置为空,从high开始扫描一个比基准tmp小的元素:while(low<high && R[high].key>tmp.key) high--;
③把找到的比tmp小的元素放在基准左边,也就是low的位置:R[low]=R[high];
④high所指位置为空,从low开始扫描一个比基准tmp大的元素:while(low<high && R[low].key<tmp.key) low++;
⑤把找到的比tmp大的元素放在基准右边,也就是high的位置:R[high]=R[low];
⑥重复上述操作,直到low=high,即可找到基准tmp的最终位置:R[low]=tmp;
⑦返回基准所在位置,用于设置新的左右子树:return low;
(3)算法:
int partition(Elemtype R[],int low,int high)
{
Elemtype tmp;
tmp=R[low]; //以最左边的值为基准
while(low<high) //当low=high时跳出循环,是基准的最终位置
{
while(low<high && R[high].key>tmp.key) //从右至左找到一个比基准小的元素
high--;
R[low]=R[high]; //放在基准左边
while(low<high && R[low].key<tmp.key) //从左往右找到一个比基准大的元素
low++;
R[high]=R[low];
}
R[low]=tmp; //是基准的最终位置
return low; //返回基准位置用于左右子树的划分
}
void QuickSort(Elemtype R[],int low,int high)
{
int i;
if(low<high)
{
i=partition(R,low,high);
QuickSort(R,low,i-1);
QuickSort(R,i+1,high);
}
}
(4)算法分析:
与递归层数有关,当序列为逆序或正序时会呈现最坏的情况。
空间复杂度:O(递归层数) 平均:O(log2n)
时间复杂度:O(n*递归层数) 平均:O(nlog2n)
不稳定的算法
二、习题总结
1.李春葆例题
以参考书为例:“一次划分”算“一趟”,与408试题不同。
2.王道选择题
(1)快速排序最快:全等分;快速排序最慢:逆序或正序。
(2)冒泡排序可从前往后冒,也可以从后往前冒。
(3)内排序一般采用的存储方式都是顺序存储。
(4)对尚未确定最终位置的所有元素进行一遍处理称为一趟的话,第二趟只有两个合适结果那么其中一个必定是端点,否则得有三个合适结果。