算法筆記(二) 排序之冒泡排序和快速排序

冒泡排序

思路

1.循環獲取列表每一個元素

2.將該元素與其它元素比較交換,篩選出最大元素

代碼

java版本

/**
 * Created by lilongsheng on 2017/6/20.
 */
public class BubbleSort {
    public static void main(String[] args) {
        int[] score = {11, 64, 33, 79, 55, 66, 77, 23};
        bubbleSort(score);
    }

    public static void bubbleSort(int[] score) {
        //外層循環n-1次
        for (int i = 1; i < score.length; i++) {
            StringBuilder sb = new StringBuilder();
            int temp = 0;
            for (int j = 0; j < score.length - i; j++) {
                sb.append(" O ");
                if (score[j] > score[j + 1]) {
                    temp = score[j + 1];
                    score[j + 1] = score[j];
                    score[j] = temp;
                }
            }
            System.out.println(sb.append(" ").append(score[score.length-i]));
        }
        for (int a = 0; a < score.length; a++) {
            System.out.print(score[a] + "\t");
        }
    }
}

效果如下:
這裏寫圖片描述

python版本


  1 def bubble_sort(scores):
  2         for i in range(len(scores)-1,-1,-1):
  3                 for j in range(i):
  4                         if (scores[j] > scores[j+1] ):
  5                                 scores[j+1],scores[j] = scores[j],scores[j+1]
  6 
  7         for m in scores:
  8                 print(m)

複雜度

時間

       時間複雜度即循環的次數,外層循環n-1次,內層循環最好爲1次,最壞爲n次,由此可推出爲1到2的和,爲如下圖:
這裏寫圖片描述

時間複雜度圖形

這裏寫圖片描述

空間

       它的空間複雜度是佔用額外空間內存,循環裏面只用到了一個temp臨時變量,即空間複雜度爲O(1)

實際應用

       據說冒泡排序是最慢的排序算法,可以當做給初學者講解for循環、分析算法複雜度時的案例來講,冒泡排序的作用遠不止這些,它的思想值得我們學習,如果沒有冒泡排序後面的各種優化排序也就不能夠被髮明出來,冒泡排序在算法中的地位好比 “Hello World” 在編程語言中的地位,理解了Hello World也就理解了冒泡。

快速排序

思路

代碼

java版本

/**
 * Created by lilongsheng on 2017/6/20.
 */
public class QuickSort {

    public static void main(String[] args) {
        int[] arrayData = new int[]{26, 53, 67, 48, 57, 13, 48, 32, 60, 50 };

        QuickSort qs = new QuickSort();
        qs.quickSort(arrayData,0,9);

        for (int i : arrayData){
            System.out.println(i);
        }
    }

    /**
     * 快速排序一個已知數組
     * @param arrayData
     * @param left
     * @param right
     */
    public void quickSort(int[] arrayData,int left,int right){
        //出口必須有,否則right會減成負數,程序死循環
        if (right <= left) return;
        //選擇軸值
        int pivot = selectPivot(left,right);
        //軸值與數組元素換位置(任意位置即可)
        swap(arrayData,pivot,right);
        //根據軸值分成兩組
        pivot = partition(arrayData,left,right);
        //左邊數組繼續分組
        quickSort(arrayData,left,pivot-1);
        //右邊數組繼續分組
        quickSort(arrayData,pivot+1,right);

    }

    /**
     * 軸值選取(影響排序性能,可優化)
     * @param left
     * @param right
     * @return
     */
    public int selectPivot(int left,int right){
        return (left + right) / 2;
    }

    public void swap(int[] arrayData,int pivot,int right){
        int temp = arrayData[right];
        arrayData[right] = arrayData[pivot] ;
        arrayData[pivot] = temp;
    }

    /**
     * 根據軸值對數組分爲大小兩組
     * @param arrayData
     * @param left
     * @param right
     * @return
     */
    public int partition(int[] arrayData,int left,int right){

        int l = left;
        int r = right;
        int temp = arrayData[r];
        //從左右兩端像中間循環
        while (l < r){
            //從左像右找 大於等於軸值得數據
            while ( arrayData[l] <= temp && l < r){
                l++;
            }
            if (l < r){
                arrayData[r] = arrayData[l];
                r--;
            }
            //從右像左找 小於等於軸值得數據
            while ( arrayData[r] >= temp && l < r){
                r--;
            }
            if (l < r){
                arrayData[l] = arrayData[r];
                l++;
            }
        }
        //循環結束時 l = r ,即軸值位置
        arrayData[l] = temp;

        return l;
    }
}

python版本

 1 # 快速排序入口函數
  2 def quick_sort(datas,left,right):
  3         print('開始快速排序')
  4         # 出口
  5         if (right <= left ): return
  6         # 選取軸值(可以自定義位置)
  7         pivot = select_pivot(left,right)
  8         print('軸值=='+str(pivot))
  9         # 將軸值與任何一個值互換
 10         swap(datas,pivot,right)
 11 
 12         # 計劃軸值新位置
 13         pivot = partition(datas,left,right)
 14         print('pivot==' + str(pivot))
 15 
 16         quick_sort(datas,left,pivot-1)
 17         quick_sort(datas,pivot+1,right)
 18 
 19         for x in datas:
 20                 print('x='+str(x))
 21 
 22 
 23 # 選取軸值方法
 24 def select_pivot(left,right):
 25         return int((left + right) / 2)
  1 # 快速排序入口函數
  2 def quick_sort(datas,left,right):
  3         print('開始快速排序')
  4         # 出口
  5         if (right <= left ): return
  6         # 選取軸值(可以自定義位置)
  7         pivot = select_pivot(left,right)
  8         print('軸值=='+str(pivot))
  9         # 將軸值與任何一個值互換
 10         swap(datas,pivot,right)
 11 
 12         # 計劃軸值新位置
 13         pivot = partition(datas,left,right)
 14         print('pivot==' + str(pivot))
 15 
 16         quick_sort(datas,left,pivot-1)
 17         quick_sort(datas,pivot+1,right)
 18 
 19         for x in datas:
 20                 print('x='+str(x))
 21 
 22 
 23 # 選取軸值方法
 24 def select_pivot(left,right):
 25         return int((left + right) / 2)
 26 
 27 # 將軸值與任意一個數字交換
 28 def swap(datas,pivot,right):
 29         datas[pivot],datas[right] = datas[right],datas[pivot]
 30 
 31 # 根據軸值充分分組
 32 def partition(datas,left,right):
 33         l = left
 34         r = right
 35         temp = datas[r]
 36 
 37         while (l < r):
 38                 # 從左像右遍歷,如果有大於軸值得,移動到右側
 39                 while ( datas[l] <= temp and l < r ):
 40                         l += 1
 41                 if ( l < r ):
 42                         datas[r] = datas[l]
 43                         r -= 1
 44                 # 從右側向左遍歷,如果有小雨軸值得,移動到左側
 45                 while ( datas[r] >= temp and l < r ):
 46                         r -= 1
 47                 if ( l < r ):
 48                         datas[l] = datas[r]
 49                         l += 1
 50 
 51         datas[l] = temp
 52         # 返回軸值位置,l = r
 53         return l
 54 
 55 
 56 # 1. python 實現注意  print 時 注意str 變量不能默認類型轉換  python是動態類型語言
 57 # 2. python 語言的i++  i-- 類似語法不支持,使用 i-=1 表示 i-- ,   i+=1 表示 i++

複雜度

時間

  • 最壞:O(n2)
  • 平均:O(nlogn)
  • 最好:O(nlogn)

空間

-均分時:O(logn)
關於複雜度的推導在後續文章中繼續介紹。

實際應用

       對於某個排序算法的應用其實並不多,查了一下資料是否使用某個算法要結合其它條件來選取,比如n的大小、是否穩定、是否有序、輔助空間大小等等,綜合內外因素來選取具體某個排序算法或者組合算法。

思考:

1.冒泡排序與快速排序之間的關係?

       快速排序可以看做是冒泡排序的優化,它運用了分治法的基礎思想,每次分治法分組時利用的是比較交換排序,可以這樣理解:冒泡 + 分治 + 分組 = 快速。

2.快速排序是如何想出來的?

       快速排序由C. A. R. Hoare在1962年提出,距離現在已經有近60年,爲什麼會有人能想出來這麼快的算法呢,任何新方法新技術的產生都是在原有基礎上的創新或優化,各行各業亦如此,想必發明快速排序的作者對冒泡排序和其它理論基礎知識廖記於心。
       很多優秀的算法都是重複利用以前的計算結果而不用重新計算提高效率,快速排序之所以快是因爲考慮到了兩個問題
- 分治分組
- 怎麼分

       怎麼分對於快速排序是重點,快速排序中通過選取一個值將數組分爲小於該數的數組和大於該數的數組,每次排序既把選取元素的位置確定了,也基本確定了左右元素的活動範圍,因此,它的排序效率很高。

如何優化快速排序?

       優化快速排序還需要從它的特點入手,怎麼分組的問題,分組時越精準那麼以後排序的次數也就越少,從理論上說可以選取任意數組中元素,我們選取的元素越能靠近中間值元素,排序越少。

3.學習發明輪子的思想?

       知識只有轉化生產力纔能有價值,學富五車也不如將其部分應用於實踐,想要將自己所學應用於實踐就必須知道它的本質特性、融會貫通,對於算法也是如此,如果只死記硬背一些算法應付考試,就不能夠在生活中、工作中發揮出其價值來,最終發揮其作用纔是我們不斷學習的動力。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章