算法篇1:排序算法(上篇)
一:常见算法的复杂度及稳定性
二:冒泡排序
基本方法:
比较两个相邻的元素,将值大的元素交换至右端
举例说明:
初始需排序数组 int[] arr = {6,3,8,2,9,1};
第一趟排序:
第一次排序:6和3比较,6大于3,交换位置: 3 6 8 2 9 1
第二次排序:6和8比较,6小于8,不交换位置:3 6 8 2 9 1
第三次排序:8和2比较,8大于2,交换位置: 3 6 2 8 9 1
第四次排序:8和9比较,8小于9,不交换位置:3 6 2 8 9 1
第五次排序:9和1比较:9大于1,交换位置: 3 6 2 8 1 9
第一趟总共进行了5次比较, 排序结果: 3 6 2 8 1 9
第一趟比较完成后,最后一个数一定是数组中最大的一个数,所以第二趟比较的时候最后一个数不参与比较;
————————————————————————————————————
第二趟排序:
第一次排序:3和6比较,3小于6,不交换位置:3 6 2 8 1 9
第二次排序:6和2比较,6大于2,交换位置: 3 2 6 8 1 9
第三次排序:6和8比较,6大于8,不交换位置:3 2 6 8 1 9
第四次排序:8和1比较,8大于1,交换位置: 3 2 6 1 8 9
第二趟总共进行了4次比较, 排序结果: 3 2 6 1 8 9
第二趟比较完成后,倒数第二个数也一定是数组中第二大的数,所以第三趟比较的时候最后两个数不参与比较;
———————————————————————————————————————
第三趟排序:
第一次排序:3和2比较,3大于2,交换位置: 2 3 6 1 8 9
第二次排序:3和6比较,3小于6,不交换位置:2 3 6 1 8 9
第三次排序:6和1比较,6大于1,交换位置: 2 3 1 6 8 9
第二趟总共进行了3次比较, 排序结果: 2 3 1 6 8 9
第三趟完成后,倒数第三个也是数组中第三大的数,·······以后也是一样
——————————————————————————————————————
第四趟排序:
第一次排序:2和3比较,2小于3,不交换位置:2 3 1 6 8 9
第二次排序:3和1比较,3大于1,交换位置: 2 1 3 6 8 9
第二趟总共进行了2次比较, 排序结果: 2 1 3 6 8 9
——————————————————————————————————————
第五趟排序:
第一次排序:2和1比较,2大于1,交换位置: 1 2 3 6 8 9
第二趟总共进行了1次比较, 排序结果: 1 2 3 6 8 9
——————————————————————————————————————
代码实现:
1 package com.xqc.sort; 2 3 public class BubleSort { 4 public static void main(String[] args) { 5 //步骤1:初始化数组 6 int[] arr={6,3,8,2,9,1}; 7 System.out.println("排序前数组为:"); 8 for(int num:arr){ 9 System.out.println(num+""); 10 } 11 //步骤二:冒泡排序 12 for(int i=0;i<arr.length-1;i++){//外层循环控制排序趟数 13 for(int j=0;j<arr.length-1-i;j++){//内层循环控制每一趟排序多少次 14 if(arr[j]>arr[j+1]){ 15 int temp=arr[j]; 16 arr[j]=arr[j+1]; 17 arr[j+1]=temp; 18 } 19 } 20 21 } 22 //步骤三:显示排序后数组 23 System.out.println(); 24 System.out.println("排序后的数组为:"); 25 for(int num:arr){ 26 System.out.println(num+" "); 27 } 28 } 29 }
三:选择排序
基本方法:
每一次从待排序的数据元素中选出最小的一个元素,存放在待排序序列的起始位置,直到全部排完
举例说明:
初始需排序数组:int[] arr = {6,3,8,2,9,1}
第一趟排序:待排序数组为 { 6,3,8,2,9,1 } 中最小的数据是【1】,则将【1】和第一个数据 【6】做交换
结果为{1,3,8,2,9,6}
————————————————————————————————————
第二趟排序:此时未排序数组为{3,8,2,9,6}中最小的数据是【2】,则将【2】与第一个数据【3】做交换
结果为{1,2,8,3,9,6}
————————————————————————————————————
第三趟排序:此时未排序数组为{8,3,9,6}中最小的数据是【3】,则将【3】与第一个数据【8】进行交换
结果为{ 1,2,3,8,9,6}
————————————————————————————————————
第四趟排序:此时未排序数组为{8,9,6}中最小数据是【6】,则将【6】与第一个数据【8】进行交换
结果为{1,2,3,6,9,8}
————————————————————————————————————
第五趟排序:此时未排序数组为{9,8}中最小数据是【8】,则将【8】与第一个数据【9】进行交换
结果为{1,2,3,6,8,9}
代码实现:
1 package com.xqc.sort; 2 3 public class SeclectionSort { 4 public static void main(String[] args) { 5 //步骤1:初始化数组 6 int[] arr={6,3,8,2,9,1}; 7 System.out.println("排序前数组为:"); 8 for(int num:arr){ 9 System.out.println(num+""); 10 } 11 //步骤二:选择排序 12 for(int i = 0; i < arr.length - 1; i++) {// 做第i趟排序 13 int k = i; 14 for(int j = k + 1; j < arr.length; j++){// 选最小的记录 15 if(arr[j] < arr[k]){ 16 k = j; //记下目前找到的最小值所在的位置 17 } 18 } 19 //在内层循环结束,也就是找到本轮循环的最小的数以后,再进行交换 20 if(i != k){ //交换a[i]和a[k] 21 int temp = arr[i]; 22 arr[i] = arr[k]; 23 arr[k] = temp; 24 } 25 } 26 27 //步骤三:显示排序后数组 28 System.out.println(); 29 System.out.println("排序后的数组为:"); 30 for(int num:arr){ 31 System.out.println(num+" "); 32 } 33 } 34 }
四:直接插入排序:
基本方法:
每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。
举例说明:
初始需排序数组:int[] arr = {6,3,8,2,9,1}
(第一趟:从上述初始数组中取出第一个数【6】,把他插入到有序表中
结果为:有序表{ 6 },无序表:{ 3,8,2,9,1} )
有的会在代码中显示该步骤,有的直接跳过这步会
————————————————————————————————————
第二趟:从上述无序表中取出第一个数【3】,,把他插入到有序表的合适位置
结果为:有序表{ 3,6},无序表{8,2,9,1}
————————————————————————————————————
第三趟:从上述无序表中取出第一个数【8】,,把他插入到有序表的合适位置
结果为:有序表{ 3,6,8},无序表{2,9,1}
————————————————————————————————————
第四趟:从上述无序表中取出第一个数【2】,,把他插入到有序表的合适位置
结果为:有序表{ 2,3,6,8},无序表{9,1}
————————————————————————————————————
第五趟:从上述无序表中取出第一个数【9】,,把他插入到有序表的合适位置
结果为:有序表{ 2,3,6,8,9},无序表{1}
————————————————————————————————————
第六趟:从上述无序表中取出第一个数【1】,,把他插入到有序表的合适位置
结果为:有序表{ 1,2,3,6,8,9},无序表{}
————————————————————————————————————
代码实现:
1 package com.xqc.sort; 2 3 public class InsertSort { 4 public static void main(String[] args) { 5 //步骤1:初始化数组 6 int[] arr={6,3,8,2,9,1}; 7 System.out.println("排序前数组为:"); 8 for(int num:arr){ 9 System.out.println(num+""); 10 } 11 //步骤二:插入排序 12 //从未排序的序列中取出第一个 13 for(int i=1;i<arr.length;i++){ 14 int tempdata = arr[i]; 15 int j; 16 //寻找合适的插入位置,从后往前走,如果大与这个数则将这个数往后移动一 17 for(j=i-1;j>=0;j--){ 18 if(arr[j]>tempdata){ 19 arr[j+1] = arr[j]; 20 }else{ 21 break; 22 } 23 } 24 //寻找到合适位置,将取出的数放在该位置 25 arr[j+1] = tempdata; 26 } 27 28 //步骤三:显示排序后数组 29 System.out.println(); 30 System.out.println("排序后的数组为:"); 31 for(int num:arr){ 32 System.out.println(num+" "); 33 } 34 } 35 }
五:快速排序:
基本思路:
快速排序是找出一个元素(理论上可以随便找一个)作为基准(pivot),然后对数组进行分区操作,使基准左边元素的值都不大于基准值,基准右边的元素值 都不小于基准值,如此作为基准的元素调整到排序后的正确位置。递归快速排序,将其他n-1个元素也调整到排序后的正确位置。最后每个元素都是在排序后的正 确位置,排序完成。
举例说明:
初始需排序数组:int[] = {3,7,2,9,1,4,6,8,10,5}(这次换个数组,并不是什么原因,我只是想在一次排序中让他体现出所有的情况)
第一趟:选取基准值【5】
第一次:从左边开始,将每个数与基准值比较,直到找到比基准值大的【7】,调换【5】和【7】的位置,因为【7】必须要在基准【5】的右边,则结果:
比基准【5】小的有 {3} ,没有排序的有{5,2,9,1,4,6,8,10},比基准5大的有{7}
第二次:从右边开始,将每个数与基准值比较,直到找到比基准值小的【4】,然后交换【4】和【5】的位置,则结果为
比基准【5】小的有{3,4},没有排序的有{ 2,9,1,5},比基准大的有{ 6,8,10,7}
第三次:从左边开始,将每个数与基准值比较,直到找到比基准值大的【9】,调换【5】和【9】的位置,则结果为
比基准【5】小的有{3,4,2} 未排序的有{5,1},比基准大的有{ 9,6,8,10,7 }
第四次:从右边开始,将每个数与基准值比较,直到找到比基准值小的【1】,然后交换【1】和【5】的位置,则结果为
比基准【5】小的有{3,4,2,1} 基准值 { 5 }比基准大的有{ 9,6,8,10,7 }
第二趟:重复上述步骤,分别对{3,4,2,1} 和 {9,6,8,10,7}进行递归式快排
······
代码实现:
1 package com.xqc.sort; 2 3 public class QuickSort { 4 5 public static void main(String[] args) { 6 //步骤1:初始化数组 7 int[] arr={3,7,2,9,1,4,6,8,10,5}; 8 System.out.println("排序前数组为:"); 9 for(int num:arr){ 10 System.out.println(num+""); 11 } 12 //步骤二:快速排序,因为要进行递归,所以我就将改方法提取出来 13 sort(arr, 0, arr.length-1); 14 15 16 //步骤三:显示排序后数组 17 System.out.println(); 18 System.out.println("排序后的数组为:"); 19 for(int num:arr){ 20 System.out.println(num+" "); 21 } 22 } 23 24 /** 25 * 将数组的某一段元素进行划分,小的在左边,大的在右边 26 * @param a 27 * @param start 28 * @param end 29 * @return 30 */ 31 public static int divide(int[] a, int start, int end){ 32 //每次都以最右边的元素作为基准值 33 int base = a[end]; 34 //start一旦等于end,就说明左右两个指针合并到了同一位置,可以结束此轮循环。 35 while(start < end){ 36 while(start < end && a[start] <= base) 37 //从左边开始遍历,如果比基准值小,就继续向右走 38 start++; 39 //上面的while循环结束时,就说明当前的a[start]的值比基准值大,应与基准值进行交换 40 if(start < end){ 41 //交换 42 int temp = a[start]; 43 a[start] = a[end]; 44 a[end] = temp; 45 //交换后,此时的那个被调换的值也同时调到了正确的位置(基准值右边),因此右边也要同时向前移动一位 46 end--; 47 } 48 while(start < end && a[end] >= base) 49 //从右边开始遍历,如果比基准值大,就继续向左走 50 end--; 51 //上面的while循环结束时,就说明当前的a[end]的值比基准值小,应与基准值进行交换 52 if(start < end){ 53 //交换 54 int temp = a[start]; 55 a[start] = a[end]; 56 a[end] = temp; 57 //交换后,此时的那个被调换的值也同时调到了正确的位置(基准值左边),因此左边也要同时向后移动一位 58 start++; 59 } 60 61 } 62 //这里返回start或者end皆可,此时的start和end都为基准值所在的位置 63 return end; 64 } 65 66 /** 67 * 排序 68 * @param a 69 * @param start 70 * @param end 71 */ 72 public static void sort(int[] a, int start, int end){ 73 if(start > end){ 74 //如果只有一个元素,就不用再排下去了 75 return; 76 } 77 else{ 78 //如果不止一个元素,继续划分两边递归排序下去 79 int partition = divide(a, start, end); 80 sort(a, start, partition-1); 81 sort(a, partition+1, end); 82 } 83 84 } 85 86 }