1. 程式人生 > >資料結構圖文解析之:直接插入排序及其優化(二分插入排序)解析及C++實現

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

0. 資料結構圖文解析系列

1. 插入排序簡介

插入排序是一種簡單直觀的排序演算法,它也是基於比較的排序演算法。它的工作原理是通過不斷擴張有序序列的範圍,對於未排序的資料,在已排序中從後向前掃描,找到相應的位置並插入。插入排序在實現上通常採用就地排序,因而空間複雜度為O(1)。在從後向前掃描的過程中,需要反覆把已排序元素逐步向後移動,為新元素提供插入空間,因此插入排序的時間複雜度為O(n^2);

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)。二分插入排序的主要操作為比較+後移賦值,則:

  • 最壞情況:每次都在有序序列的起始位置插入,則整個有序序列的元素需要後移,時間複雜度為O(n^2)
  • 最好情況:待排序陣列本身就是正序的,每個元素所在位置即為它的插入位置,此時時間複雜度僅為比較時的時間複雜度,為O(log2n)
  • 平均情況:O(n^2)

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

3.3. 穩定性

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

相關推薦

資料結構圖文解析直接插入排序及其優化二分插入排序解析C++實現

0. 資料結構圖文解析系列 1. 插入排序簡介 插入排序是一種簡單直觀的排序演算法,它也是基於比較的排序演算法。它的工作原理是通過不斷擴張有序序列的範圍,對於未排序的資料,在已排序中從後向前掃描,找到相應的位置並插入。插入排序在實現上通常採用就地排序,因而空間複雜度為O(1)。在從後向前掃描的過程中,需要反

資料結構圖文解析哈夫曼樹與哈夫曼編碼詳解C++模板實現

0. 資料結構圖文解析系列 1. 哈夫曼編碼簡介 哈夫曼編碼(Huffman Coding)是一種編碼方式,也稱為“赫夫曼編碼”,是David A. Huffman1952年發明的一種構建極小多餘編碼的方法。 在計算機資料處理中,霍夫曼編碼使用變長編碼表對源符號進行編碼,出現頻率較高的源符號採用較短的編碼,

mooc浙大資料結構PTA習題最大子列和問題2線上處理

01-複雜度2 Maximum Subsequence Sum(25 分) Given a sequence of K integers { N​1​​, N​2​​, ..., N​K​​ }. A continuous subsequence is defined to

白話空間統計Moran&#39;s I莫蘭指數

元素 cal ltr div sdn glob 之間 計算 fonts 前兩天聊了空間統計學裏面的兩個經典概念,今天來說說第一篇文章留下的大坑:Moran‘s I。 首先,Moran‘s I這個東西。官方叫做:莫蘭指數,是澳大利亞統計學家帕特裏克·阿爾弗雷德·

資料結構】二叉樹的建立和遍歷非遞迴

該程式使用的是遞迴地建立方法,以及非遞迴的遍歷演算法 執行環境:Dev-C++ #include <stdio.h> #include <stdlib.h> typedef struct node{ char data; struct node *lchild

ZeroMQ介面函式 zmq_inproc – ØMQ 本地程序內執行緒間傳輸方式

————————————————————————————————————— zmq_inproc(7)   ØMQ Manual - ØMQ/4.2.0 Name zmq_inproc – ØMQ 本地程序內(執行緒間)傳輸方式 Synopsis 程序內傳輸方式意味著在共享ZMQ con

資料結構與演算法】Huffman樹&&Huffman編碼附完整原始碼

出處:http://blog.csdn.net/ns_code/article/details/19174553 Huffman Tree簡介     赫夫曼樹(Huffman Tree),又稱最優二叉樹,是一類帶權路徑長度最短的樹。假設有n個權值{w1,

資料結構與算法系列----多源最短路徑Floyd-Warshall演算法

任意兩點最短路徑被稱為多源最短路徑,即給定任意兩個點,一個出發點,一個到達點,求這兩個點的之間的最短路徑,就是任意兩點最短路徑問題,多源最短路徑,而Floyd-Warshall演算法最簡單,只有5行程式碼,即可解決這個問題。 上圖中有4個城市8條公路,公路上的數字表示這條

資料結構】高效雙向連結串列list、樹tree二叉樹

vi正常模式下: "shift + g" 跳到最後一行 "gg" 跳到第一行 <效率更高的雙向連結串列結構程式碼>/*程式碼*/ 01link.c #include <stdlib.h> #include "01link.h" //連結串列初始化 v

BZOJ - 5427最長上升子序列 二分&思維

現在給你一個長度為n的整數序列,其中有一些數已經模糊不清了,現在請你任意確定這些整數的值, 使得最長上升子序列最長。(為何最長呢?因為hxy向來對自己的rp很有信心)   Input 第一行一個正整數n 接下來n行第i行格式如下

插入排序演算法+優化 二分查詢優化有序部分C語言實現

直接插入排序 插入排序思想        直接插入排序思想是將待排序的陣列看作兩個部分:有序部分和無序部分,排序過程就是不斷將無序部分的元素插入到有序部分合適的位置上,使有序部分元素不斷增加而無序部分資料不斷減少,直到陣列全部有序為止。         假設陣列A[0...

動態規劃最長上升子序列二分演算法 nlogn

解題心得: 1、在資料量比較大的時候n^2會明顯超時,所以可以使用nlogn 的演算法,此演算法少了雙重迴圈,用的lower_bound(二分法)。 2、lis中的數字並沒有意義,僅僅是找到最小點lis[0]和最大點lis[len],其中,在大於lis[le

資料結構圖文解析樹的簡介二叉排序C++模板實現.

  閱讀目錄 0. 資料結構圖文解析系列 1. 樹的簡介 1.1 樹的特徵 1.2 樹的相關概念 2. 二叉樹簡介 2.1 二叉樹的定義 2.2 斜樹、滿二叉樹、完全二叉樹、二叉查詢樹 2

資料結構圖文解析佇列詳解與C++模板實現

正文 回到頂部 0. 資料結構圖文解析系列 回到頂部 1. 佇列簡介 回到頂部 1.1 佇列的特點 佇列(Queue)與棧一樣,是一種線性儲存結構,它具有如下特點: 佇列中的資料元素遵循“先進先出”(First In First Out)的原則,簡稱FI

資料結構圖文解析二叉堆詳解C++模板實現

0. 資料結構圖文解析系列 1. 二叉堆的定義 二叉堆是一種特殊的堆,二叉堆是完全二叉樹或近似完全二叉樹。二叉堆滿足堆特性:父節點的鍵值總是保持固定的序關係於任何一個子節點的鍵值,且每個節點的左子樹和右子樹都是一個二叉堆。 當父節點的鍵值總是大於或等於任何一個子節點的鍵值時為最大堆。 當父節點的鍵值總是小於

資料結構圖文解析陣列、單鏈表、雙鏈表介紹C++模板實現

0. 資料結構圖文解析系列 1. 線性表簡介 線性表是一種線性結構,它是由零個或多個數據元素構成的有限序列。線性表的特徵是在一個序列中,除了頭尾元素,每個元素都有且只有一個直接前驅,有且只有一個直接後繼,而序列頭元素沒有直接前驅,序列尾元素沒有直接後繼。 資料結構中常見的線性結構有陣列、單鏈表、雙鏈表、迴圈

資料結構圖文解析棧的簡介C++模板實現

0. 資料結構圖文解析系列 1. 棧的簡介 1.1棧的特點 棧(Stack)是一種線性儲存結構,它具有如下特點: 棧中的資料元素遵守”先進後出"(First In Last Out)的原則,簡稱FILO結構。 限定只能在棧頂進行插入和刪除操作。 1.2棧的相關概念 棧的相關概念: 棧頂與棧底:允許元素

資料結構圖文解析二分查詢與其相關的幾個問題解析

0. 資料結構圖文解析系列 1. 二分查詢簡介 二分查詢大家都不陌生,可以說除了最簡單的順序查詢之外,我們第二個接觸的查詢演算法就是二分查找了。順序查詢的時間複雜度是O(n),二分查詢的時間複雜度為O(logn)。在面試中二分查詢被考察的概率還是比較高的,上次去面試時就遇到手寫二分查詢的題目。二分查詢不難,

資料結構與演算法直接插入排序

一、前言直接插入排序(Insertion Sort)序是一種最簡單的插入排序。為簡化問題,在此我們只討論升序排序。二、演算法思想插入排序:每一趟將一個待排序的記錄,按照其關鍵字的大小插入到有序佇列的合適位置裡,直到全部插入完成。假設有一組無序序列 R0, R1, ... ,

資料結構實驗棧與佇列五下一較大值一,二

資料結構實驗之棧與佇列五:下一較大值(一,二) Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Problem Description 對於包含n(1<=n<=1000)個整數的序列,對於序