排序算法(二)

### 排序算法(二)
```c
/////////////////////////////////////////////////////////////
//歸併排序(遞歸)
//時間複雜度:O(N * logN)
//空間複雜度:O(N)
//穩定性:穩定排序
////////////////////////////////////////////////////////////

void _MergeArray(int array[], int64_t beg, int64_t mid,  int64_t end, int* tmp){
    int64_t cur1 = beg;
    int64_t cur2 = mid;
    int64_t tmp_index = beg;
    while(cur1 < mid && cur2 < end){
        if(array[cur1] < array[cur2]){
            tmp[tmp_index++] = array[cur1++];
        }else{
            tmp[tmp_index++] = array[cur2++];
        }
    }
    while(cur1 < mid){
        tmp[tmp_index++] = array[cur1++];
    }
    while(cur2 < end){
        tmp[tmp_index++] = array[cur2++];
    }
    //進行歸併的時候處理的區間是 array[beg, end),
    //對應的會把這部分區間元素填充到 tmp[beg, end)
    memcpy(array + beg, tmp + beg, sizeof(int) * (end - beg));
    return;
}

void _MergeSort(int array[], int64_t beg, int64_t end, int* tmp){
    if(end - beg <= 1){
        //要麼一個元素,要麼沒有元素,要麼非法區間
        return;
    }
    int64_t mid = beg +(end - beg) / 2;
    //此時有了兩個區間[beg, mid), [mid, end)
    _MergeSort(array, beg, mid, tmp);
    _MergeSort(array, mid, end, tmp);
    _MergeArray(array, beg, mid,  end, tmp);
    return;
}

void MergeSort(int array[], size_t size){
    int* tmp = (int*)malloc(sizeof(int) * size); 
    _MergeSort(array, 0, size, tmp);
    free(tmp);
}


/////////////////////////////////////////////////////////////
//歸併排序
//時間複雜度:O(N * logN)
//空間複雜度:O(N)
//穩定性:穩定排序
////////////////////////////////////////////////////////////

void MergeSortByLoop(int array[], size_t size){
    if(size <= 1){
        return;
    }
    int* tmp = (int*)malloc(sizeof(int) * size);
    size_t gap = 1;
    for(; gap < size; gap *= 2){
        //在當前gap下,使用i幫助我們完成所有長度爲gap的區間合併
        size_t i = 0;
        for(;i < size; i += 2 * gap){
            size_t beg = i;
            size_t mid = i + gap;
            //爲了防止 mid超出數組最大size
            if(mid > size){
                mid = size;
            }
            size_t end = i + 2 * gap;
            if(end > size){
                end = size;
            }
            _MergeArray(array, beg, mid, end, tmp);
        }
    }
    free(tmp);
}


/////////////////////////////////////////////////////////////
//快速排序
//時間複雜度:O(N * logN) 最壞情況O(N ^ 2)
//空間複雜度:最壞O(N)
//穩定性:不穩定排序
////////////////////////////////////////////////////////////

//取一個基準值,倒騰,使前半部分小於基準值,後半部分大於基準值
//如果逆序,快排就不合適,遞歸可能很深,針對小數組不合適
// C++ STL std::sort
// 1.選取基準值的的方法:三個元素選中間值
// 2.當遞歸深度達到一定值的時候,就不在繼續遞歸,而是把排序算法轉化成堆排序
// 3.當遞歸達到一定程度之後,子區間的元素個數已經比較小,把排序算法編程插入排序

//交換法
int64_t Partion(int array[], int64_t beg, int64_t end){
    if(end - beg <= 1){
        return beg;
    }
    int64_t left = beg;
    int64_t right = end - 1;
    //數組的最後一個元素作基準元素
    int key = array[right];
    //從左往右找一個大於key的值
    while(left < right){
        while(left < right && array[left] <= key){
            ++left;
        }
        //從右往左找一個小於key的值
        while(left < right && array[right] >= key){
            --right;
        }
        if(left < right){
            Swap(&array[left], &array[right]);
        }
    }
    //最後把left指向的位置和基準值交換
    Swap(&array[left], &array[end - 1]);
    return left;
}

void  _QuickSort(int array[], int64_t beg, int64_t end){
    if(end - beg <= 1){
        return;
    }
    //[beg, mid),左半區間
    //[mid + 1, end],右半區間
    //
    int64_t mid = Partion(array, beg, end);
    _QuickSort(array, beg, mid);
    _QuickSort(array, mid + 1, end);
}

void QuickSort(int array[], size_t size){
    _QuickSort(array, 0, size);
    return;
}

//挖坑法
int64_t Partion2(int array[], int64_t beg, int64_t end){
    if(end - beg <= 1){
        return beg;
    }
    int64_t left = beg;
    int64_t right = end - 1;
    //數組的最後一個元素作基準元素
    int key = array[right];
    while(left < right){
        while(left < right && array[left] <= key){
            ++left;
        }
        if(left < right){
            array[right--] = array[left];
        }
        while(left < right && array[right] >= key){
            --right;
        }
        //循環可以退出,意味着 right 指向了一個小於基準值的元素,
        //就可以把這個值填到剛纔left 指向的坑裏
        //一旦複製操作完成,right自身又成了一個坑
        if(left < right){
            array[left++] = array[right];
        }
    }
    //一旦left 和right重合,說明整個區間整理完畢
    //但是還有一個坑
    array[left] = key;
    return left;
}

//3.雙指針前移法
//略

//非遞歸版本快速排序
void QuickSortByLoop(int array[], size_t size){
    if(size <= 1){
        return;
    }
    LinkStack stack;
    LinkStackInit(&stack);
    int64_t beg = 0;
    int64_t end = size;
    LinkStackPush(&stack, beg);
    LinkStackPush(&stack, end);
    while(1){
        int ret = LinkStackTop(&stack, &end);
        if(ret == 0){
            //棧爲空,說明排序結束
            break;
        }
        LinkStackPop(&stack);
        LinkStackTop(&stack, &beg);
        if(end - beg <= 1){
            continue;
        }
        int64_t mid = Partion(array,beg, end);
        LinkStackPush(&stack, beg);
        LinkStackPush(&stack, mid);
        LinkStackPush(&stack, mid + 1);
        LinkStackPush(&stack, end);
    }
}

/////////////////////////////////////////////////////////////
//計數排序
/////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////
//奇數排序
/////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////
//睡眠排序:創建線程,根據退出時間
/////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////
//猴子排序:無線猴子定理
/////////////////////////////////////////////////////////////

“`

發佈了66 篇原創文章 · 獲贊 22 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章