算法篇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 }

 

 

 

 

 

 

posted @ 2018-08-26 14:37  阿苍老师  阅读(322)  评论(3编辑  收藏  举报