一、冒泡排序
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。 一个具有注脚的文本。
举个例子
利用冒泡排序对下面 n 个元素按照从大到小的顺序进行排序: [1, 5, 3, 9, 12, 7, 15, 10]
排序过程
对于例中的 n 个元素的排序过程如下:
Tip: 相邻元素比较次数为 n-1 次
Java语言实现
public class Sort {
public static void bubbleSort(int[] arr) {
for(int i = 1; i < arr.length; i++) {
boolean flag = false;
for(int j = 0; j < arr.length-i; j++) {
if(arr[j] < arr[j+1]) {
int t = arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
flag = true;
}
}
if(flag == false){
break;
}
}
}
}
Tip: 这里使用 flag 来处理已经排序好的情况
测试结果
public class Test {
public static void main(String[] args) {
int[] arr = new int[]{1,5,3,9,12,7,15,10};
Sort.bubbleSort(arr);
for(int a: arr) {
System.out.println(a);
}
}
}/*output:
[15, 12, 10, 9, 7, 5, 3, 1]
*/
C语言实现
#include<stdio.h>
int main() {
int arr[100];
int n = 0;
int i;
printf("请输入排序数组:");
while(true){
scanf("%d",&arr[n]);
n++;
if(getchar() == ' ')
continue;
else
break;
}
for(i = 1; i < n; i++) {
bool flag = false;
for(int j = 0; j < n - i; j++) {
if(arr[j] < arr[j+1]) {
int t = arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
flag = true;
}
}
if(flag == false){
break;
}
}
printf("排序完成:[");
for(i = 0; i < n; i++){
printf("%d",arr[i]);
if(i != n - 1)
printf(", ");
}
printf("]\n");
return 0;
}
测试结果
时间复杂度分析
最好的情况下:元素已经按照大小顺序排序,只需要比较 n-1 次,时间复杂度为 O(n)
最坏的情况下:元素按照倒序排序,需要执行 n (n - 1) 次比较,时间复杂度为O( n2 )
二、选择排序
在未排序的序列中找到最大(最小值)依次有序放入排序好的序列中。
举个例子
利用选择排序对下面 n 个元素按照从大到小的顺序进行排序: [1, 5, 3, 9, 12, 7, 15, 10]
排序过程
Java语言实现
public class Sort {
public static void selectSort(int[] arr) {
int maxId;
for(int i = 0; i < arr.length; i++) {
maxId = i;
for(int j = i+1; j < arr.length; j++) {
if(arr[j] > arr[maxId]) {
maxId = j;
}
}
int t = arr[i];
arr[i] = arr[maxId];
arr[maxId] = t;
}
}
}
测试结果
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
int[] arr = new int[] {1, 5, 3, 9, 12, 7, 15, 10};
Sort.selectSort(arr);
System.out.println(Arrays.toString(arr));
}
}/*output:
[15, 12, 10, 9, 7, 5, 3, 1]
*/
时间复杂度分析
选择排序无论是哪个元素进去,都要进行两次循环操作,所以时间复杂度为 O(n2)
三、快速排序
快速排序采用分治法进行排序,算法思路:
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
举个例子
利用快速排序对下面 n 个元素按照从大到小的顺序进行排序: [1, 5, 3, 9, 12, 7, 15, 10]
排序过程
快速排序可以拆分为:挖坑填数 + 分治,具体的排序过程可以参见:快速排序-菜鸟教程
Java语言实现
public static void quickSort(int[] nums, int l, int r){
if(l > r || l == r)
return;
int key = nums[l];
int i = l, j = r;
while(i < j){
while(i < j && (nums[j] < key || nums[j] == key)){
j--;
}
if (i < j){
nums[i] = nums[j];
i++;
}
while(i < j && nums[i] > key){
i++;
}
if (i < j) {
nums[j] = nums[i];
j--;
}
}
nums[i] = key;
quickSort(nums,l,i-1);
quickSort(nums,i+1,r);
}
时间复杂度分析
快速排序可以分为两段程序:排序和分区
假设比较 n 个元素,则需要 n 次才能完成排序;然后,计算出分区的个数:
分区个数为 1 ……分区长度为 n
分区个数为 2 ……分区长度为 n / 2
分区个数为 3 ……分区长度为 n / 22
以此类推下去,则分区个数为 t 时,分区的长度为 n / 2t-1 ,由此可以得到分区个数 t 和 元素个数 n 的关系 t = n / 2t-1 即 t = logn。(每个分区,都需要进行一次排序)
平均时间复杂度为:O(nlogn)
当我们选择的基数,始终是每个区间或子区间的最大(小)值,就会出现 n 个分区,由此计算出最坏时间复杂度为 O(n2)