數據結構圖文解析之:直接插入排序及其優化(二分插入排序)解析及C++實現

0. 數據結構圖文解析系列

數據結構系列文章
數據結構圖文解析之:數組、單鏈表、雙鏈表介紹及C++模板實現
數據結構圖文解析之:棧的簡介及C++模板實現
數據結構圖文解析之:隊列詳解與C++模板實現
數據結構圖文解析之:樹的簡介及二叉排序樹C++模板實現.
數據結構圖文解析之:AVL樹詳解及C++模板實現
數據結構圖文解析之:二叉堆詳解及C++模板實現
數據結構圖文解析之:哈夫曼樹與哈夫曼編碼詳解及C++模板實現
數據結構圖文解析之:直接插入排序及其優化(二分插入排序)解析及C++實現
數據結構圖文解析之:二分查找及與其相關的幾個問題解析

1. 插入排序簡介

插入排序是一種簡單直觀的排序算法,它也是基於比較的排序算法。它的工做原理是經過不斷擴張有序序列的範圍,對於未排序的數據,在已排序中從後向前掃描,找到相應的位置並插入。插入排序在實現上一般採用就地排序,於是空間複雜度爲O(1)。在從後向前掃描的過程當中,須要反覆把已排序元素逐步向後移動,爲新元素提供插入空間,所以插入排序的時間複雜度爲O(n^2);html

2. 直接插入排序圖解

通常來講,插入排序都採用在數組上就地排序實現。具體算法描述以下:算法

  1. 從第一個元素開始,該元素能夠認爲已經被排序
  2. 取出下一個元素,在已經排序的元素序列中從後向前掃描
  3. 若是該元素(已排序)大於新元素,將該元素移到下一位置
  4. 重複步驟3,直到找到已排序的元素小於或者等於新元素的位置
  5. 將新元素插入到該位置後
  6. 重複步驟2~5

假設咱們要對數組{12,4,5,2,6,14}進行插入排序,排序過程爲:
數組

2.1. 代碼實現

template <typename T>
void InsertSort(T array[],int length)
{
    if (array == nullptr || length < 0)
        return;
    int i, j;
    for (i = 1; i < length; i++)
    {
        if (array[i]<array[i - 1])
        {
            int temp = array[i];     
            for (j = i - 1; array[j]>temp; j--) //元素後移
            {
                array[j + 1] = array[j];
            }
            array[j+1] = temp;        //在合適的位置上出入元素
        }
    }
}

2.2. 複雜度分析

  • 插入排序的最好狀況是數組已經有序,此時只須要進行n-1次比較,時間複雜度爲O(n);
  • 最壞狀況是數組逆序排序,此時須要進行n(n-1)/2次比較以及n-1次賦值操做(插入);
  • 平均來講插入排序算法的複雜度爲O(n^2)。

插入排序不適合對大量數據進行排序應用,但排序數量級小於千時插入排序的效率還不錯,能夠考慮使用。插入排序在STL的sort算法和stdlib的qsort算法中,都將插入排序做爲快速排序的補充,用於少許元素的排序(一般爲8個或如下)。數據結構

直接插入排序採用就地排序,空間複雜度爲O(1).函數

2.3. 穩定性

直接插入排序是穩定的,不會改變相同元素的相對順序。優化

3. 二分查找插入排序

上面的插入排序實現中,爲了找到元素的合適的插入位置,咱們採用從後到前遍歷的順序查找進行比較,爲了減小比較的次數,咱們能夠換種查找策略:採用二分查找
咱們定義一個二分查找函數,函數返回插入位置的下標:編碼

/*二分查找函數,返回插入下標*/
template <typename T>
int BinarySearch(T array[], int start, int end, T k)
{
    while (start <= end)
    {
        int middle = (start + end) / 2;
        int middleData = array[middle];
        if (middleData > k)
        {
            end = middle - 1;
        }
        else
            start = middle + 1;
    }
    return start;
}
//二叉查找插入排序
template <typename T>
void InsertSort(T array[], int length)
{
    if (array == nullptr || length < 0)
        return;
    int i, j;
    for (i = 1; i < length; i++)
    {
        if (array[i]<array[i - 1])
        {
            int temp = array[i];
            int insertIndex = BinarySearch(array, 0,i, array[i]);//使用二分查找在有序序列中進行查找,獲取插入下標
            for (j = i - 1; j>=insertIndex; j--) //移動元素
            {
                array[j + 1] = array[j];   
            }       
            array[insertIndex] = temp;    //插入元素
        }
    }
}

3.2. 複雜度分析

咱們這個二分查找的算法並不會由於等於某一個值而中止查找,它將查找整個序列直到start<=end條件不知足而獲得插入的位置,因此對於長度爲n的數組來講,比較次數爲log2n ,時間複雜度爲O(log2n)。二分插入排序的主要操做爲比較+後移賦值,則:code

  • 最壞狀況:每次都在有序序列的起始位置插入,則整個有序序列的元素須要後移,時間複雜度爲O(n^2)
  • 最好狀況:待排序數組自己就是正序的,每一個元素所在位置即爲它的插入位置,此時時間複雜度僅爲比較時的時間複雜度,爲O(log2n)
  • 平均狀況:O(n^2)

空間複雜度上, 二分插入排序也是就地排序算法,它的空間複雜度爲O(1).htm

3.3. 穩定性

二分插入排序是穩定的。元素的相對順序在排序後不會被改變。blog

原創文章,轉載請註明: http://www.cnblogs.com/QG-whz/p/5194569.html

相關文章
相關標籤/搜索