排序算法複習

//
// Created by NickWang on 2019/8/24.
//

/*
 直接插入排序-----O(n^2)
 折半插入排序-----O(n^2)
 冒泡排序--------O(n^2)
 快速排序--------O(nlogn)
 選擇排序--------O(n^2)
 堆排序----------O(nlogn)
 歸併排序--------O(nlogn)

 */

#ifndef C_SORT_H
#define C_SORT_H

#include <iostream>
#include <vector>
using namespace std;


class Sort {
public:

    /*
     * 直接插入排序 O(n^2)
     * 算法思想:將記錄集合分爲有序和無序兩個序列。
     * 從無序序列中任取一個記錄,根據大小插入到有序序列的合適位置,使得該序列插入後仍然有序。
     * 每插入一個記錄稱爲一趟插入排序,無序記錄全部插入有序序列後,排序完成
     */
    void DirectInsert(int data[], int n){
        for (int i = 1; i < n; ++i) { // 一共執行n-1趟
            int currentNum = data[i]; // 保存當前處理的值
            int index = i - 1; // 記錄上一個值得索引號

            // 從上一個開始往前找,只要比當前處理的數大,就將數值後移
            while (index >= 0 && currentNum < data[index])
            {
                data[index + 1] = data[index];
                index--;
            }
            data[index + 1] = currentNum;
        }
    }

    /*
     * 折半插入排序 O(n^2)
     * 算法思想:在直接插入排序的基礎上,由於有序序列可以折半查找,找到合適位置後進行移位。
     */
    void BinaryInsert(int data[], int n){
        int low, high, mid, currentNum;
        for (int i = 1; i < n; ++i) { // 一共執行n-1趟
            low = 0;
            high = i - 1;
            currentNum = data[i];

            while (low <= high){
                mid = (low + high) / 2;
                if (currentNum < data[mid]){
                    // 在前半段
                    high = mid - 1;
                } else {
                    low = mid + 1;
                }
            }

            // 插入位置爲high + 1
            for (int j = i - 1; j >= high + 1; --j) {
                data[j + 1] = data[j];
            }
            data[high + 1] = currentNum;
        }
    }

    /*
     * 冒泡排序 O(n^2)
     * 算法思想:兩兩比較待排記錄大小,發現逆序,交換兩個記錄,直到表中沒有逆序記錄存在
     */
    void BubbleSort(int data[], int n){
        int swap = 0;
        for (int i = 0; i < n - 1; ++i) { // 一共執行n-1趟
            for (int j = 1; j < n - 1 - i; ++j) {
                if (data[j - 1] > data[j]){
                    int temp = data[j - 1];
                    data[j - 1] = data[j];
                    data[j] = temp;
                    swap = 1;
                }
            }

            // 沒有進行交換,說明已經排好序
            if (swap == 0){
                break;
            }
        }
    }

    /*
     * 快速排序 O(nlogn)
     * 算法思想:在待排序列中任取一個記錄,以該記錄爲基準,經過一趟交換後,
     * 所有比記錄小的都在左邊,比記錄大的都在右邊。
     * 然後在對左右兩部分重複上述步驟。
     */
    int Partition(int data[], int i, int j){
        // 保存基準數據
        int baseNum = data[i];

        while (i < j){
            // 從j開始從右往左找第一個比基準小的數據
            while (i < j && data[j] > baseNum)
                j--;
            if (i < j){
                // 找到第一個比baseNum小的數字,將小數放到左邊界,左邊界右移,i++
                data[i] = data[j];
                i++;
            }

            // 從左邊界開始往右找第一個比基準大的數據
            while (i < j && data[i] < baseNum)
                i++;
            if (i < j){
                // 找到第一個比baseNum大的數字,將大數放到右邊界,右邊界左移,--j
                data[j] = data[i];
                --j;
            }
        }

        // i 的位置就是基準數據該在的位置
        data[i] = baseNum;
        return i;
    }

    void QuickSort(int data[], int low, int high){
        if (low < high){
            int location = Partition(data, low, high);
            QuickSort(data, low, location - 1);
            QuickSort(data, location + 1, high);
        }
    }

    /*
     * 選擇排序 O(n^2)
     * 算法思想:每一趟選擇待排記錄中最小的記錄,並放入已排序序列的末尾,
     * 直至全部記錄完成。
     */
    void SelectSort(int data[], int n){
        for (int i = 0; i < n - 1; ++i) {
            int min = i;
            for (int j = i + 1; j < n; ++j) {
                if (data[j] < data[min])
                    min = j;
            }

            if (min != i){
                int temp = data[min];
                data[min] = data[i];
                data[i] = temp;
            }
        }
    }

    /*
     * 堆排序 O(nlogn)
     * 算法思想:(小頂堆爲例)由堆頂可以得到最小值,然後將其移除,
     * 對剩餘n-1個節點進行調整,重新成爲一個堆,再從堆頂獲取最小值。
     * 當堆只剩下一個數據的時候,將其移除後就排成有序序列。
     *
     * 數組存儲二叉樹說明:
     * 父節點序號爲i,2i爲其左孩子,2i+1爲其右孩子 (從1開始存)
     * 共n個節點,則大於n/2的節點開始爲葉子節點
     *
     * 建立初始堆:
     * 大於n/2的節點爲葉子節點,本事滿足堆的定義。
     * 於是從n/2節點開始,將其調整爲堆。然後對n/2-1調整爲堆。
     * 對節點i調整過程中,調整時可能使本來滿足堆定義的子樹不再滿足,
     * 於是需要逐層向下進行調整。
     *
     * 堆頂去除後,剩餘n-1節點調整成新堆:
     * 將序號爲n的節點與堆頂交換,這時只需要使1~n-1滿足堆的定義,
     * 即可將剩餘n-1節點構成堆。這時對堆頂元素進行自上而下的調整。
     * 調整方法:將根節點與左右孩子中較小的交換,然後繼續對交換後的子樹進行交換,
     * 直到交換到葉子節點。
     */
    void HeapAdjust(int data[], int begin, int end){
        data[0] = data[begin]; // 保存堆頂元素
        int currentIndex = begin; // 保存正在操作的節點序號

        // 堆頂元素從較小的孩子開始向下調整
        for (int i = 2 * begin; i <= end; i = i * 2) {
            if (i < end && data[i] > data[i + 1]){
                // 左孩子比右孩子大
                i = i + 1; // 選擇較小的
            }

            if (data[0] < data[i]){
                // 此時堆頂的最小,則無需向下調整
                break;
            }
            data[currentIndex] = data[i];
            currentIndex = i;
        }
        data[currentIndex] = data[0]; // 將堆頂放到合適位置
    }

    void HeapSort(int data[], int n){
        for (int i = n / 2; i > 0; --i) {
            HeapAdjust(data, i, n);
        }

        // 每一趟堆頂和最後一個換
        for (int i = n; i > 1; --i) {
            // data[1]和當前最後一個data[i]進行交換
            data[0] = data[1];
            data[1] = data[i];
            data[i] = data[0];
            HeapAdjust(data, 1, i - 1);
        }
    }

    /*
     * 歸併排序 O(nlogn)
     * 算法思想:只有一個記錄的表是有序的,開始將n個記錄看成n個表,每個表有序。
     * 第一趟二路歸併將表1和表2,表3和表4,...,表n-1和表n進行歸併,得到長度爲2的表。
     * 繼續重複得到長度爲4的表,...,直到最後將整個表歸併。
     */
    void merge(int data[], int retData[], int begin, int mid, int end){
        // 將有序表data[begin:mid]與data[mid:end]合併成一個有序表retData[begin:end]
        int i = begin;
        int j = mid + 1;
        int k = begin;
        while (i <= mid && j <= end){
            if (data[i] < data[j])
                retData[k++] = data[i++];
            else
                retData[k++] = data[j++];
        }

        // data[begin:mid]還沒有完
        while (i <= mid){
            retData[k++] = data[i++];
        }

        // data[mid:end]還沒有完
        while (j <= end){
            retData[k++] = data[j++];
        }
    }

    void MergeSort(int data[], int retData[], int begin, int end){
        // 將無序表data[begin:end]合併成有序表retData[begin:end]
        int tempData[255];

        if (begin == end){
            retData[begin] = data[begin];
        } else {
            int mid = (begin + end) / 2;
            MergeSort(data, tempData, begin, mid);
            MergeSort(data, tempData, mid + 1, end);
            merge(tempData, retData, begin, mid, end);
        }
    }



};







#endif //C_SORT_H

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