排序算法复习

//
// 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

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