最近了解了一下在面试题中,会经常遇到的一些常见的简单的排序的算法
在这里做个简单的记录如有不对之处请多指教。
1、冒泡排序
算法思想:冒泡排序是对数组中相邻的两个元素进行比较,看是否满足大小关系,不满足的话就交换位置
每次冒泡排序至少有一个元素到达指定位置,也至少会发生一次位置交换(如果没有位置交换就说明数组有序),
有n个数据,需要重复n次
最好、最坏、平均时间复杂度:
最好时间复杂度(是一个有序数组时)为O(n)
最坏时间复杂度(刚好倒序时)为O(n2)
平均时间复杂度:O(n2)
代码示例:
1 public static void bubbleSort(int[] arr) { 2 for (int i = 0; i < arr.length - 1; i++) { 3 for (int j = 0; j < arr.length - 1 - i; j++) { 4 if(arr[j] > arr[j+1]) { 5 int temp = arr[j]; 6 arr[j] = arr[j + 1]; //数据交换 7 arr[j+1] = temp; 8 } 9 } 10 } 11 }
冒泡排序的一些小的优化:当某次冒泡,没有再进行数据的交换时,说明数组已经有序,就可以不用进行后面的冒泡操作了
代码示例:
1 public static void bubbleSort(int[] arr) { 2 3 if(arr.length <= 1) return; 4 5 for(int i = 0;i < arr.length - 1;i++) { 6 boolean flag = false; //提前退出循环的标志 7 for(int j = 0;j < arr.length - i -1;j++) { 8 if(arr[j] > arr[j + 1]) { 9 int temp = arr[j]; 10 arr[j] = arr[j + 1]; //数据交换 11 arr[j + 1] = temp; 12 flag = true; //表示有数据交换 13 } 14 } 15 if (!flag) break; //如果没有数据交换的话退出循环 16 } 17 }
运行结果:
2、选择排序
算法思想:在未排序区间寻找最小的数据,将其放到已排好序区间的元素的尾部
最好、最坏、平均时间复杂度:
最好时间复杂度:O(n2)
最坏时间复杂度:O(n2)
平均时间复杂度:O(n2)
代码示例:
1 public static void selectionSort(int[] arr) { 2 for(int i = 0;i < arr.length - 1;i++) { 3 int minIndex = i; 4 //选出未排序区间的最小元素 5 for (int j = i + 1; j < arr.length; j++) { 6 if(arr[j] < arr[minIndex]) { 7 minIndex = j; 8 } 9 } 10 if(minIndex == i) 11 continue; 12 //交换位置 13 int temp = arr[i]; 14 arr[i] = arr[minIndex]; 15 arr[minIndex] = temp; 16 } 17 18 }
运行结果:
3、插入排序
算法思想:我们将元素分为两个区间,未排序区间和已排序区间。
在未排序区间取出元素与已排序区间元素进行比较插入到适当位置,
以此类推,直到未排序区间为空为止
最好时间复杂度:(数组有序)O(n)
最坏时间复杂度:(刚好倒序)O(n2)
平均时间复杂度:O(n2)
4、归并排序
算法思想:利用归并的思想方法实现的一种有效的排序方法,采用经典的分治策略。
最好时间复杂度:O(nlogn)
最坏时间复杂度:O(nlogn)
平均时间复杂度:O(nlogn)
代码示例:
1 public class MergeSort { 2 public static void main (String[] args) { 3 int[] arr = {56,12,97,58,64,25}; 4 sort(arr); 5 print(arr); 6 } 7 8 public static void print(int[] arr) { 9 for(int i = 0;i < arr.length;i++){ 10 System.out.print(arr[i] + " "); 11 } 12 } 13 14 public static void sort(int[] arr) { 15 int[] temp = new int[arr.length]; //定义一个临时数组,避免递归时频繁开辟空间 16 sort(arr,0,arr.length - 1,temp); 17 } 18 19 20 public static void sort(int[] arr,int left,int right,int[] temp) { 21 if(left < right){ 22 int mid = (left + right) / 2; 23 sort(arr,left,mid,temp); //左归并操作 24 sort(arr,mid + 1,right,temp); //右归并操作 25 mergeSort(arr,left,mid,right,temp); 26 27 } 28 29 } 30 31 //合并子序列的操作 32 private static void mergeSort(int[] arr,int left,int mid,int right,int[] temp) { 33 int i = left; 34 int j = mid + 1; 35 int k = 0; 36 37 while(left <= mid && j <= right) { //将子序列元素有序写入临时数组 38 if(arr[i] >= arr[j]) { 39 temp[k++] = arr[j++]; 40 } else { 41 temp[k++] = arr[i++]; 42 } 43 44 } 45 46 while(i <= mid) { //将左子序列元素全部写入临时数组中 47 temp[k++] = arr[i++]; 48 } 49 50 while(j <= right) { //将右子序列元素全部写入临时数组中 51 temp[k++] = arr[j]; 52 53 } 54 55 for (int t = 0;left <= right;t++) { 56 arr[left++] = temp[t]; 57 } 58 } 59 60 }
合并子序列的操作图解。可以用Debug调试,进入程序查看具体的运算,这里只做个简单的图解。
运行的结果: