排序算法中的小技巧

https://blog.csdn.net/neverwa/article/details/79629314
https://blog.csdn.net/weiwenhp/article/details/8621049 
快速排序 非遞歸
https://blog.csdn.net/Arctton/article/details/4089393  使用堆棧和不使用堆棧

void MergeSortIteration(int A[], int len)    // 非遞歸(迭代)實現的歸併排序(自底向上)
{
    int left, mid, right;// 子數組索引,前一個爲A[left...mid],後一個子數組爲A[mid+1...right]
    for (int i = 1; i < len; i *= 2)        // 子數組的大小i初始爲1,每輪翻倍
    {
        left = 0;
        while (left + i < len)              // 後一個子數組存在(需要歸併)
        {
            mid = left + i - 1;
            right = mid + i < len ? mid + i : len - 1;// 後一個子數組大小可能不夠
            Merge(A, left, mid, right);
            left = right + 1;               // 前一個子數組索引向後移動
        }
    }
}

當我們利用left  mid right 進行步長i遞增的時候,如果設right=mid+i如果要保證left到mid   mid+1到right  兩個隊列數目相等。那麼這個mid就必須爲mid=left+i-1.。直觀的來講如果mid=left+i  。那麼左隊列就有1(left本身) 加i個,右隊列只有i個,不對等。所以在約束定義爲“:左隊列爲left到mid  右隊列 mid+1到right 時,應該用mid=left+i-1,right=mid+i,來保證左右隊列皆爲i個元素。或者用mid=left+i   right=mid+i+1來保證左右隊列各i+1各元素。很顯然在歸併排序中,應該使用最小粒度的分組,即爲前者。


int Partition(int A[], int left, int right)  // 劃分函數
{
    int pivot = A[right];               // 這裏每次都選擇最後一個元素作爲基準
    int tail = left - 1;                // tail爲小於基準的子數組最後一個元素的索引
    for (int i = left; i < right; i++)  // 遍歷基準以外的其他元素
    {
        if (A[i] <= pivot)              // 把小於等於基準的元素放到前一個子數組末尾
        {
            Swap(A, ++tail, i);
        }
    }
    Swap(A, tail + 1, right);           // 最後把基準放到前一個子數組的後邊,剩下的子數組即是大於基準的子數組
                                        // 該操作很有可能把後面元素的穩定性打亂,所以快速排序是不穩定的排序算法
    return tail + 1;                    // 返回基準的索引
}

在以上編碼中

int tail = left - 1;  與  
 Swap(A, ++tail, i);

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