插入排序

插入排序是一類藉助插入操做進行排序的方法,其核心思想是每次將代排序的記錄插入到有序區中並使有序區仍然有序。git

也就是說在考慮記錄Ri以前,R一、R2...,Ri-1爲有序序列,如今要將Ri插入到該有序序列適當的位置。github

插入排序可分爲直接插入排序、折半插入排序、二路插入排序和希爾排序。數組

源碼:https://github.com/fangyz/myDataStructure函數

/*直接插入排序:每次從無序區中選擇第一個插入到有序區中。
對於時間複雜度,最好狀況下數據是有序的無需移動,比較次數爲n-1;
最壞狀況下數組是一個倒序的,n-1次循環中,每次都要移動i+1次,比較次數爲i    ,時間複雜度是O(n^2);
總體來看的話,確定是要執行n次的,每次執行時比較與移動次數是n的一階函數,故平均時間複雜度也是O(n^2)。
缺點是時間複雜度爲n^2,效率較低,改進可從2個地方改進,一個是比較次數一個是移動次數。
*/
void DirectInsertSort(int *a, int length)
{
    if (a == NULL || length < 0)
        return;
    int i,index;
    int value;
    //進行i次循環,每次循環將i插入到0~i-1的有序區中
        for (i = 1; i < length; i++){
            if (a[i] < a[i - 1])
            {
                index = i;
                value = a[index];
                while (value<a[index-1]&&index>0)
                {
                    a[index] = a[index - 1];
                    index--;
                }
                a[index] = value;
            }
        }
}


//折半插入排序,就是在無序區中取出數據插入到有序區時採用折半的思想,每次是和有序區中間的數進行比較。
//它僅僅只是減小了比較的次數,移動次數沒有減小,故時間複雜度仍然爲O(n^2)。
void HalfInsertSort(int *a, int length)
{
    int i;
    int start = 0, end = 0, mid = 0;
    int currentIndex = 0;
    int temp = 0;
    if (a == NULL || length <= 0)
        return;
    for (i = 1; i<length; i++)
    {
        currentIndex = i;
        temp = a[i];
        end = i;
        mid = end;
        //目的是找到一個位置mid,a[mid]>temp而a[mid-1]是小於或等於temp的
        while (end>start&&temp<a[end - 1])
        {
            mid = (start + end) / 2;
            if (a[mid]>temp)
                end = mid;
            else
            {
                if (start == mid)
                {
                    mid++;
                    break;
                }
                start = mid;
            }
        }
        for (; currentIndex>mid; currentIndex--)
            a[currentIndex] = a[currentIndex - 1];
        a[currentIndex] = temp;
    }
}

/*希爾排序是一種分組插入排序,它的基本思想以下:
1.取一個正整數d1爲它的增量,並將整個數組分爲d1組。接下來對於k(k=0,1,2..d1-1)而言: k,k+d1,k+2d1....做爲一組進行直接插入排序。
2.對d1組進行一次直接插入排序後,再選取新的增量d2<d1繼續進行分組插入排序直到dn=1,對全部數據來一次插入排序。
思考:
剛開始接觸希爾排序以爲有點麻煩,靜下心來思考後就會發現希爾排序比直接插入排序時間複雜度低。首先循環次數將再也不是n-2次了,而是將分組的次數。
對於每一次循環時間由於仍然是直接插入排序複雜度仍然是O(n^2),但是因爲進行分組如今的n已經減少了,故Tn整體上也會減少。
並且還有一點,直接插入排序的特色是數組越有序那移動比較次數越少,希爾排序中越日後數組越有序所以效率還會提升。
查閱資料發現希爾排序的時間複雜度是一個關於增量的函數,能夠試着計算它的時間複雜度,lbd*d*O((length/d)^2)
能夠確定的是它比O(n^2)快比O(n)慢,速度僅次於快速排序。
*/

//這裏將增量d初始化爲length的一半,以後每次減半直到1
void ShellSort(int *a, int length){
    int d;                //定義增量
    int i, j;
    int temp;        //暫存量
    int index;        //須要插入的位置
    if (a == NULL || length <= 0)
        return;
    //進行lbd次循環
    for (d = length / 2; d>0; d = d / 2)
    {
        //直接插入排序的循環次數
        for (i = 0; i<d; i++)
        {
            //開始直接插入排序
            for (j = i + d; j<length; j = j + d)
            {
                index = j - d;
                temp = a[j];
                while (temp<a[index] && index >= 0)
                {
                    a[index + d] = a[index];
                    index = index - d;
                }
                a[index + d] = temp;
            }
        }
    }
}


//更好的希爾排序
void BetterShellSort(int *a, int length){
    int d;//做爲增量
    int i, j;
    int index, value;//直接插入排序須要用到的變量
    for (d = length / 2; d >= 1; d = d / 2)
    {
        //優化的思想主要是這裏,上面是對每個分組單獨放在for循環裏面去執行,可是這些分組其實就是在一條序列上的,只要相加的值不一樣仍然能夠每次與同組成員進行比較。
        for (j = d; j < length; j++){
            if (a[j] < a[j - d]){
                value = a[j];
                index = j;
                while (a[index-d]>value&&index>0)
                {
                    a[index] = a[index - d];
                    index = index - d;
                }
                a[index] = value;
            }
        }
    }
}
相關文章
相關標籤/搜索