一、冒泡排序
1. 执行过程:
原始序列:49,38,65,97,76,13,27,49
1)1号和2号比较,49>38,交换。
38,49,65,97,76,13,27,49
2)2号和3号比较,49<65,不交换。
38,49,65,97,76,13,27,49
3)3号和4号比较,65<97,不交换。
38,49,65,97,76,13,27,49
4)4号和5号比较,97>76,交换。
38,49,65,76,97,13,27,49
5)5号和6号比较,97>13,交换。
38,49,65,76,13,97,27,49
6)6号和7号比较,97>27,交换。
38,49,65,76,13,27,97,49
7)7号和8号比较,97>49,交换。
38,49,65,76,13,27,49,97
至此,一趟冒泡排序结束。
2. 算法思想:
代码:
void BubbleSort(int R[],int n)
{
int i,j,flag;
int temp;
for(i = n-1; i >= 1; --i)
{
flag = 0;
for(j = 1;j <= i;++j)
{
if(R[j-1] > R[j])
{
temp = R[j];
R[j] = R[j-1];
R[j-1] = temp;
flag = 1 //如果没发生交换,则flag为0;如果发生交换,则flag改为1
}
if(flag == 0)
return;
}
}
}
3. 复杂度分析:
(1)时间复杂度分析
由冒泡排序算法代码,可以选取最内层循环中的关键字交换操作作为基本操作。
1)最坏的情况,即整个序列是逆序的,则内层循环中if语句的条件R[j]<R[j-1]始终成立,基本操作执行的次数为n-i。i的取值为1~n-1。总执行次数为(n-1+1)(n-1)/2=n(n-1)/2,时间复杂度为O(n²)。
2)最好的情况,即整个序列已经有序,则内层循环中if语句的条件R[j]<R[j-1]始终不成立的。时间复杂度为O(n)。
综合上述两种情况,本算法的平均时间复杂度为O(n²)。
(2)空间复杂度为O(1)。
二、快速排序
1. 执行过程:
原始序列:49,38,65,97,76,13,27,49
i j(i 和 j 开始时分别指向头、尾关键字 )
进行第一趟快排,以49作为枢纽,整个过程是一个交替扫描和交换的过程。
1)使用 j ,从序列最右端开始向前扫描,直到遇到比49小的数27,j 停在这里。
49,38,65,97,76,13,27,49
i j
2)将27交换到序列前端 i 的位置。
27,38,65,97,76,13, ,49
i j
3)使用 i ,变换扫描方向,从前向后扫描,直到遇到比49大的数65,i 停在这里。
27,38,65,97,76,13, ,49
i j
4)将65交换到序列后端 j 的位置。
27,38, ,97,76,13,65,49
i j
5)使用 j ,变换扫描方向,从后向前扫描,直到遇到比49小的数13,j 停在这里。
27,38, ,97,76,13,65,49
i j
6)将13交换到序列前端 i 的位置。
27,38,13,97,76, ,65,49
i j
7)使用 i ,变换扫描方向,从前向后扫描,直到遇到比49大的数97,i 停在这里。
27,38,13,97,76, ,65,49
i j
8)将97交换到序列前端 j 的位置。
27,38,13, ,76,97,65,49
i j
9)使用 j ,变换扫描方向,从后向前扫描,直到遇到比49小的数,当i 和 j 相遇时,扫描结束。
27,38,13, ,76,97,65,49
ij
10)此时 i 等于j 的这个位置就是49的最终位置。第一趟快速排序结束。
27,38,13,49,76,97,65,49
ij
接下来,按照同样的方法对序列{27,38,13}和{76,97,65,49}分别进行排序。
2. 算法思想:
代码:
void QuickSort(int R[],int low,int high) //对从R[low]到R[r]的关键字进行排序
{
int temp;
int i = low, j = r;
if(low < high)
{
temp = R[low];
while(i != j)
{
while(i<j && R[j]>=temp)
--j; //从右往左扫描,找到一个小于temp的关键字
if(i < j)
{
R[i] = R[j];
++i;
}
while(i<j && R[i]<temp)
++i; //从左往右扫描,找到一个大于temp的关键字
if(i < j)
{
R[j] = R[i];
--j;
}
}
R[i] = temp; //将temp放在最终位置
QuickSort(R,low,i-1); //递归地对temp左边的关键字进行排序
QuickSort(R,i+1,high); //递归地对temp右边的关键字进行排序
}
}
Java代码实现:
import java.util.Arrays;
public class Main1 {
public static void main(String[] args) {
int[] a = {1, 2, 4, 5, 7, 4, 5, 3, 9, 0};
System.out.println(Arrays.toString(a));
quickSort(a);
System.out.println(Arrays.toString(a));
}
public static void quickSort(int[] a) {
if (a.length > 0) {
quickSort(a, 0, a.length - 1);
}
}
private static void quickSort(int[] a, int low, int high) {
//1,找到递归算法的出口
if (low > high) {
return;
}
//2, 存
int i = low;
int j = high;
//3,key
int key = a[low];
//4,完成一趟排序
while (i < j) {
//4.1 ,从右往左找到第一个小于key的数
while (i < j && a[j] > key) {
j--;
}
// 4.2 从左往右找到第一个大于key的数
while (i < j && a[i] <= key) {
i++;
}
//4.3 交换
if (i < j) {
int p = a[i];
a[i] = a[j];
a[j] = p;
}
}
// 4.4,调整key的位置
int p = a[i];
a[i] = a[low];
a[low] = p;
//5, 对key左边的数快排
quickSort(a, low, i - 1);
//6, 对key右边的数快排
quickSort(a, i + 1, high);
}
}
/**
* 快速排序
*
* @param array
* @param _left
* @param _right
*/
private static void quickSort(int[] array, int _left, int _right) {
int left = _left;//
int right = _right;
int pivot;//基准线
if (left < right) {
pivot = array[left];
while (left != right) {
//从右往左找到比基准线小的数
while (left < right && pivot <= array[right]) {
right--;
}
//将右边比基准线小的数换到左边
array[left] = array[right];
//从左往右找到比基准线大的数
while (left < right && pivot >= array[left]) {
left++;
}
//将左边比基准线大的数换到右边
array[right] = array[left];
}
//此时left和right指向同一位置
array[left] = pivot;
quickSort(array, _left, left - 1);
quickSort(array, left + 1, _right);
}
}
3. 复杂度分析:
(1)时间复杂度:最好的情况O(nlogn),待排序列越接近无序,算法效率越高;
最差情况O(n²),待排序列越接近有序,算法效率越低。
(2)空间复杂度为O(logn)。
快速排序是递归进行的,递归需要栈的辅助,因此它需要的辅助空间较大。