數(shù)據(jù)結(jié)構(gòu)與算法之排序(歸納總結(jié)一) -電腦資料

電腦資料 時(shí)間:2019-01-01 我要投稿
【m.clearvueentertainment.com - 電腦資料】

    排序使我們實(shí)際開發(fā)中最常使用到的幾個(gè)算法之一,按照如果按照排序過程中依據(jù)的原則對內(nèi)部排序進(jìn)行分類,則大致上可以分為插入排序、交換排序、選擇排序、歸并排序等排序方法,

數(shù)據(jù)結(jié)構(gòu)與算法之排序(歸納總結(jié)一)

。讓我們首先看看插入排序的算法有哪些,以及他們的具體實(shí)現(xiàn)。插入排序的基本排序思想是:逐個(gè)考察每個(gè)待排序元素,將每一個(gè)新元素插入到前面已經(jīng)排好序的序列中適當(dāng)?shù)奈恢蒙希沟眯滦蛄腥匀皇且粋(gè)有序序列。在這一類排序中主要介紹三種排序方法:直接插入排序、折半插入排序和希爾排序。

    1.直接插入排序

    a.算法描述

    直接插入排序是一種最簡單的插入排序方法,它的基本思想是:僅有一個(gè)元素的序列總是有序的,因此,對n個(gè)記錄的序列,可從第二個(gè)元素開始直到第n個(gè)元素,逐個(gè)向有序序列中執(zhí)行插入操作,從而得到n個(gè)元素按關(guān)鍵字有序的序列。一般來說,在含有j-1 個(gè)元素的有序序列中插入一個(gè)元素的方法是:從第j-1 個(gè)元素開始依次向前搜索應(yīng)當(dāng)插入的位置,并且在搜索插入位置的同時(shí)可以后移元素,這樣當(dāng)找到適當(dāng)?shù)牟迦胛恢脮r(shí)即可直接插入元素。以關(guān)鍵字序列{ 26 , 53 , 48 , 11 , 13 , 48, 32 , 15}為例,直接插入排序的過程如下所示。

    b:算法實(shí)現(xiàn)

    public void insertSort(int[] r, int low, int high) {

    for (int i = low + 1; i <= high; i++)

    if (compare(r[i], r[i - 1])) { // 小于時(shí),需將r[i]插入有序表

    int temp = r[i];

    r[i] = r[i - 1];

    int j = i - 2;

    for (; j >= low && compare(temp, r[j]); j--)

    r[j + 1] = r[j]; // 記錄后移

    r[j + 1] = temp; // 插入到正確位置

    }

    }

    【效率分析】

    空間效率:僅使用一個(gè)輔存單元。

    時(shí)間效率:假設(shè)待排序的元素個(gè)數(shù)為n,則向有序表中逐個(gè)插入記錄的操作進(jìn)行了n-1趟,每趟操作分為比較關(guān)鍵碼和移動記錄,而比較的次數(shù)和移動記錄的次數(shù)取決于待排序列按關(guān)鍵碼的初始排列。直接插入排序的時(shí)間復(fù)雜度為O(n²)

    c:實(shí)現(xiàn)舉例

    StraightInsertionSort.java

    package com.test.sort.insertion;

    public class StraightInsertionSort {

    /**

    * @param args

    */

    public static void main(String[] args) {

    // TODO Auto-generated method stub

    System.out.println("直接插入排序排序功能實(shí)現(xiàn)》》》》");

    int[] arr = { 23, 54, 6, 2, 65, 34, 2, 67, 7, 9, 43 };

    StraightInsertionSort sort = new StraightInsertionSort();

    System.out.println("排序之前序列:");

    sort.printArr(arr);

    sort.insertSort(arr, 0, arr.length - 1);

    System.out.println("排序之后序列:");

    sort.printArr(arr);

    }

    public void insertSort(int[] r, int low, int high) {

    for (int i = low + 1; i <= high; i++)

    if (compare(r[i], r[i - 1])) { // 小于時(shí),需將r[i]插入有序表

    int temp = r[i];

    r[i] = r[i - 1];

    int j = i - 2;

    for (; j >= low && compare(temp, r[j]); j--)

    r[j + 1] = r[j]; // 記錄后移

    r[j + 1] = temp; // 插入到正確位置

    }

    }

    public boolean compare(int paramA, int paramB) {

    if (paramA < paramB) {

    return true;

    } else {

    return false;

    }

    }

    /**

    * 依次打印出數(shù)組元素

    */

    public void printArr(int[] arr) {

    if (arr != null) {

    for (int temp : arr) {

    System.out.print(temp + " ");

    }

    System.out.println();

    }

    }

    }

    d:結(jié)果輸出

    2.希爾排序

    a.算法描述

    希爾排序又稱為“縮小增量排序”,它也是一種屬于插入排序類的排序方法,是一種對直接插入排序的改進(jìn),但在時(shí)間效率上卻有較大的改進(jìn)。從對直接插入排序的分析中知道,雖然直接插入排序的時(shí)間復(fù)雜度為O(n²),但是在待排序元素序列有序時(shí),其時(shí)間復(fù)雜度可提高至O(n)。由此可知在待排序元素基本有序時(shí),直接插入排序的效率可以大大提高。從另一方面看,由于直接插入排序方法簡單,則在n值較小時(shí)效率也較高。希爾排序正是從這兩點(diǎn)出發(fā),對直接插入排序進(jìn)行改進(jìn)而得到的一種排序方法。

    希爾排序的基本思想是:首先將待排序的元素分為多個(gè)子序列,使得每個(gè)子序列的元素個(gè)數(shù)相對較少,對各個(gè)子序列分別進(jìn)行直接插入排序,待整個(gè)待排序序列“基本有序”后,再對所有元素進(jìn)行一次直接插入排序。根據(jù)上述排序思想,下面我們給出希爾排序的排序過程:

    ⑴選擇一個(gè)步長序列t1,t2,…,tk,其中ti>tj(i

    ⑵按步長序列個(gè)數(shù)k,對待排序元素序列進(jìn)行k趟排序;

    ⑶每趟排序,根據(jù)對應(yīng)的步長ti,將待排序列分割成ti個(gè)子序列,分別對各子序列進(jìn)行直接插入排序。當(dāng)步長因子為1時(shí),所有元素作為一個(gè)序列來處理,其長度為n。以關(guān)鍵字序列{ 26 , 53 , 67 , 48 , 57 , 13 , 48, 32 , 60 , 50}為例,假設(shè)選擇的步長序列為{5 , 3 , 1},則希爾排序的過程如圖9-2所示。因?yàn)椴介L序列長度為3,因此對待排序序列一共需要進(jìn)行3趟排序。首先,第一趟排序中將關(guān)鍵字序列分成5個(gè)子序列{26 , 13},{53 , 48},{67 , 32},{48 , 60},{57 , 50},對它們分別進(jìn)行直接插入排序,結(jié)果如圖所示。然后,進(jìn)行第二趟希爾排序,此時(shí)步長為3,則將關(guān)鍵字序列分成3個(gè)子序列{13 , 48 , 53 , 57},{48, 50 , 67},{32 , 26 , 60},對它們進(jìn)行直接插入排序后的結(jié)果如圖所示。最后,對整個(gè)序列進(jìn)行一趟直接插入排序,此時(shí)得到一個(gè)關(guān)鍵字有序的序列,希爾排序結(jié)束。

    b.算法實(shí)現(xiàn)

    public void shellSort(int[] r, int low, int high, int[] delta) {

    for (int k = 0; k < delta.length; k++)

    shellInsert(r, low, high, delta[k]); // 一趟步長為delta[k]的直接插入排序

    }

    private void shellInsert(int[] r, int low, int high, int deltaK) {

    for (int i = low + deltaK; i <= high; i++)

    if (compare(r[i], r[i - deltaK])) { // 小于時(shí),需將r[i] 插入有序表

    int temp = r[i];

    int j = i - deltaK;

    for (; j >= low && compare(temp, r[j]); j = j - deltaK)

    r[j + deltaK] = r[j]; // 記錄后移 [j];

    r[j + deltaK] = temp; // 插入到正確位置

    }

    }

    【效率分析】

    空間效率:僅使用一個(gè)輔存單元。

    時(shí)間效率:假設(shè)待排序的元素個(gè)數(shù)為n,則向有序表中逐個(gè)插入記錄的操作進(jìn)行了n-1趟,每趟操作分為比較關(guān)鍵碼和移動記錄,而比較的次數(shù)和移動記錄的次數(shù)取決于待排序列按關(guān)鍵碼的初始排列。直接插入排序的時(shí)間復(fù)雜度為O(n²)

    c.使用示例

    HashInsertSort.java

    package com.test.sort.insertion;

    public class HashInsertSort {

    /**

    * @param args

    */

    public static void main(String[] args) {

    // TODO Auto-generated method stub

    System.out.println("希爾排序功能實(shí)現(xiàn)》》》》");

    int[] arr = { 23, 54, 6, 2, 65, 34, 2, 67, 7, 9, 43 };

    int[] delta = {5,3,1};

    HashInsertSort sort = new HashInsertSort();

    System.out.println("排序之前序列:");

    sort.printArr(arr);

    sort.shellSort(arr, 0, arr.length - 1,delta);

    System.out.println("排序之后序列:");

    sort.printArr(arr);

    }

    public void shellSort(int[] r, int low, int high, int[] delta) {

    for (int k = 0; k < delta.length; k++)

    shellInsert(r, low, high, delta[k]); // 一趟步長為delta[k]的直接插入排序

    }

    private void shellInsert(int[] r, int low, int high, int deltaK) {

    for (int i = low + deltaK; i <= high; i++)

    if (compare(r[i], r[i - deltaK])) { // 小于時(shí),需將r[i] 插入有序表

    int temp = r[i];

    int j = i - deltaK;

    for (; j >= low && compare(temp, r[j]); j = j - deltaK)

    r[j + deltaK] = r[j]; // 記錄后移 [j];

    r[j + deltaK] = temp; // 插入到正確位置

    }

    }

    public boolean compare(int paramA, int paramB) {

    if (paramA < paramB) {

    return true;

    } else {

    return false;

    }

    }

    /**

    * 依次打印出數(shù)組元素

    */

    public void printArr(int[] arr) {

    if (arr != null) {

    for (int temp : arr) {

    System.out.print(temp + " ");

    }

    System.out.println();

    }

    }

    }

    d.結(jié)果輸出

    3.折半插入排序

    a.算法描述

    直接插入排序算法簡便、容易實(shí)現(xiàn),

電腦資料

數(shù)據(jù)結(jié)構(gòu)與算法之排序(歸納總結(jié)一)》(http://m.clearvueentertainment.com)。當(dāng)待排序元素的數(shù)量n很小時(shí),這是一種較好的排序方法,但是通常待排序元素?cái)?shù)量n很大,則不宜采用直接插入排序方法,此時(shí)需要對直接插入排序進(jìn)行改進(jìn)。直接插入排序的基本操作是向有序序列中插入一個(gè)元素,插入位置的確定是通過對有序序列中元素按關(guān)鍵字逐個(gè)比較得到的。既然是在有序序列中確定插入位置,則可以不斷二分有序序列來確定插入位置,即搜索插入位置的方法可以使用折半查找實(shí)現(xiàn)。

    b.算法實(shí)現(xiàn)

    public void binInsertSort(int[] r, int low, int high) {

    for (int i = low + 1; i <= high; i++) {

    int temp = r[i]; // 保存待插入元素

    int hi = i - 1;

    int lo = low; // 設(shè)置初始區(qū)間

    while (lo <= hi) { // 折半確定插入位置

    int mid = (lo + hi) / 2;

    if (compare(temp, r[mid]))

    hi = mid - 1;

    else

    lo = mid + 1;

    }

    for (int j = i - 1; j > hi; j--)

    r[j + 1] = r[j]; // 移動元素

    r[hi + 1] = temp; // 插入元素

    }// for

    }

    【效率分析】

    空間效率:僅使用一個(gè)輔存單元。

    時(shí)間效率:折半插入排序僅減少了元素的比較次數(shù),但是并沒有減少元素的移動次數(shù),折半插入排序的時(shí)間復(fù)雜度為O(n²)。

    c.應(yīng)用舉例

    BinaryInsertSort.java

    package com.test.sort.insertion;

    public class BinaryInsertSort {

    /**

    * @param args

    */

    public static void main(String[] args) {

    // TODO Auto-generated method stub

    System.out.println("折半插入排序排序功能實(shí)現(xiàn)》》》》");

    int[] arr = { 23, 54, 6, 2, 65, 34, 2, 67, 7, 9, 43 };

    BinaryInsertSort sort = new BinaryInsertSort();

    System.out.println("排序之前序列:");

    sort.printArr(arr);

    sort.binInsertSort(arr, 0, arr.length - 1);

    System.out.println("排序之后序列:");;

    sort.printArr(arr);

    }

    public void binInsertSort(int[] r, int low, int high) {

    for (int i = low + 1; i <= high; i++) {

    int temp = r[i]; // 保存待插入元素

    int hi = i - 1;

    int lo = low; // 設(shè)置初始區(qū)間

    while (lo <= hi) { // 折半確定插入位置

    int mid = (lo + hi) / 2;

    if (compare(temp, r[mid]))

    hi = mid - 1;

    else

    lo = mid + 1;

    }

    for (int j = i - 1; j > hi; j--)

    r[j + 1] = r[j]; // 移動元素

    r[hi + 1] = temp; // 插入元素

    }// for

    }

    public boolean compare(int paramA, int paramB) {

    if (paramA < paramB) {

    return true;

    } else {

    return false;

    }

    }

    /**

    * 依次打印出數(shù)組元素

    */

    public void printArr(int[] arr) {

    if (arr != null) {

    for (int temp : arr) {

    System.out.print(temp + " ");

    }

    System.out.println();

    }

    }

    }

最新文章