简单描述
交换排序是指通过比较键值的大小来交换这两个元素的位置,实现排序. 常见的交换排序有冒泡排序和快速排序. 冒泡排序的时间复杂度度是 O(n^2), 快速排序的时间复杂度度是 O(nlogn), 快速排序是对冒泡排序的改良.但是快速排序是不稳定的
冒泡排序
原理:
通过比较相邻两个数的大小来决定是否交换。
一轮比较下来,最右边的数就是最大或最小的,假设数组size=n,则需要n-1轮比较。
实现:
利用外层for循环控制比较轮数,内层for循环遍历比较相邻元素(j与j+1比较)。每轮过后,有序队列就会增加一个元素。如果在某轮比较中未交换元素, 则说明元素已是有序,不用在比较了.直接break.
完整代码
void sort(int arr[],int length)
{
int i, j, flag;
for(i = 0;i < length-1; i++)
{
for(j = 0; j < length-i-1; j++)
{
flag = 1;
if(arr[j] > arr[j+1])
{
flag = 0;
arr[j+1] += arr[j];
arr[j] = (arr[j+1] - arr[j]);
arr[j+1] = (arr[j+1] - arr[j]);
}
}
if(flag)
break;
}
}
快速排序
原理:
快速排序是交换排序和分治思想的结合,其实现思路是通过一次交换,是数组的一边比另一边大,以两边的分界点,将数组分成两部分.然后分别对两边再经行同样的操作,这样不断细分下去.直到两边都只剩一个元素为止,此时数组就是有序的了.
实现:
按上述分析, 数组的拆分可以使用递归实现, 这里重点分析一趟排序的过程原理. 完成一趟排序, 要实现将一个集合分成一边大一边小的两个集合, 就需要有一个比较基准(key), key的选择对于排序效率也有影响. 这里暂不考虑,直接选择集合的第一个元素作为key. 定义两个下标i和 j 。 i = 集合开始下边,j = 集合最后一个元素的下边。i 从左向右遍历元素,j则相反。
i和j从两头出发交替遍历元素,j先开始 如果j遍历遇到比key小的元素则与i交换,然后i遍历到比key大的元素则让他与j交换。然后直到i和j相遇(i>=j)完成一趟排序。然后以i的值作为中点分割集合,再分别递归即可。
完整代码
void Quicksort(int arr[],int left,int right){
int l = left, r = right;
int key;
if(left >= right){return;}//递归结束条件
key = arr[left];
while(left < right){
//这里是arr[right] >= key,如果是arr[right] > key,当有相同的键值时会死循环.
while(arr[right] >= key && right > left)
right--;
//这里的j和i的交换由于记录了i的值(key = arr[i]),所以直接覆盖即可,下面的i与j交换也直接覆盖,循环结束后再将key复制回来
arr[left] = arr[right];
while(arr[left] < key && left < right)
left++;
arr[right] = arr[left];
}
arr[left] = key;
Quicksort(arr,l,left-1);
Quicksort(arr,left+1,r);
}