zoukankan      html  css  js  c++  java
  • 数据结构与算法复习(一) 排序算法

    这篇文章将会介绍常见的排序算法(使用 C++ 实现)

    1、冒泡排序

    将数组分为有序区(左边)和无序区(右边),在初始化时有序区为空,无序区包含数组所有元素

    每次从无序区的最后一个元素开始,一直向前冒泡到无序区的第一个位置,使其变成有序

    template<typename E>
    void swap(E A[], int i, int j) {
        E temp = A[i];
        A[i] = A[j];
        A[j] = temp;
    }
    
    template<typename E>
    void bubbleSort(E A[], int n) {
        for (int i = 0; i < n - 1; i++) {
            for (int j = n - 1; j > i; j--) {
                if (A[j] < A[j - 1]) {
                    swap(A, j, j - 1);
                }
            }
        }
    }
    

    2、选择排序

    将数组分为有序区(左边)和无序区(右边),在初始化时有序区为空,无序区包含数组所有元素

    每次从无序区中选择一个合适的元素,并将其交换到无序区的第一个位置,使其变成有序

    template<typename E>
    void swap(E A[], int i, int j) {
        E temp = A[i];
        A[i] = A[j];
        A[j] = temp;
    }
    
    template<typename E>
    void selectionSort(E A[], int n) {
        for (int i = 0; i < n - 1; i++) {
            int minIdx = i;
            for (int j = i; j <= n - 1; j++) {
                if (A[j] < A[minIdx]) minIdx = j;
            }
            swap(A, i, minIdx);
        }
    }
    

    3、插入排序

    将数组分为有序区(左边)和无序区(右边),在初始化时有序区包含数组的第一个元素,无序区包含其余的元素

    每次将无序区中的第一个元素,一直向前交换到有序区中的合适位置,使其变成有序

    template<typename E>
    void swap(E A[], int i, int j) {
        E temp = A[i];
        A[i] = A[j];
        A[j] = temp;
    }
    
    template<typename E>
    void insertionSort(E A[], int n) {
        for (int i = 1; i < n; i++) {
    		for (int j = i; j > 0; j--) {
                if (A[j] < A[j - 1]) {
                    swap(A, j, j - 1);
                }
            }
    	}
    }
    

    4、归并排序

    递归进行,每次将数组一分为二,然后对两个数组分别排序后,合并两个数组

    template<typename E>
    void mergeSort(E A[], E T[], int l, int r) {
        if (l == r) return;
        int m = (l + r) / 2;
        mergeSort<E>(A, T, l, m);
        mergeSort<E>(A, T, m + 1, r);
        // merge
        for (int k = l; k <= r; k++) T[k] = A[k];
        int i = l, j = m + 1;
        for (int c = l; c <= r; c++) {
            if (i > m) A[c] = T[j++];
            else if (j > r) A[c] = T[i++];
            else if (T[i] < T[j]) A[c] = T[i++];
            else A[c] = T[j++];
        }
    }
    

    优化:临时数组后半部分反向插入,这样可以不用检测边界情况

    template<typename E>
    void mergeSort(E A[], E T[], int l, int r) {
        if (l == r) return;
        int m = (l + r) / 2;
        mergeSort<E>(A, T, l, m);
        mergeSort<E>(A, T, m + 1, r);
        // merge
        for (int k = l; k <= m; k++) T[k] = A[k];
        for (int k = 1; k <= r - m; k++) T[r - k + 1] = A[k + m];
        int i = l, j = r;
        for (int c = l; c <= r; c++) {
            if (T[i] < T[j]) A[c] = T[i++];
            else A[c] = T[j--];
        }
    }
    

    5、快速排序

    递归进行,每次在数组中选择一个基准,根据基准将数组一分为二,然后对两个数组分别排序后,拼接两个数组

    template<typename E>
    void swap(E A[], int i, int j) {
        E temp = A[i];
        A[i] = A[j];
        A[j] = temp;
    }
    
    template<typename E>
    void quickSort(E A[], int l, int r) {
        if (r <= l) return;
        // find pivot
        int pivotIndex = (l + r) / 2;
        E pivot = A[pivotIndex];
        // put pivot at last
        swap(A, pivotIndex, r);
        // partition
        int i = l - 1;
        int j = r;
        do {
            while (A[++i] < pivot) {}
            while (i < j && pivot < A[--j]) {}
            swap(A, i, j);
        } while (i < j);
        // put pivot in place
        swap(A, r, i);
        // recursive
        quickSort(A, l, i - 1);
        quickSort(A, i + 1, r);
    }
    

    优化:使用栈替代递归

    template<typename E>
    void swap(E A[], int i, int j) {
        E temp = A[i];
        A[i] = A[j];
        A[j] = temp;
    }
    
    template<typename E>
    void quickSort(E A[], int l, int r) {
        int stack[200];
        int top = -1;
        stack[++top] = l;
        stack[++top] = r;
        while (top > 0) {
            // pop the stack
            r = stack[top--];
            l = stack[top--];
            // find pivot
            int pivotIndex = (l + r) / 2;
            E pivot = A[pivotIndex];
            // put pivot at last
            swap(A, pivotIndex, r);
            // partition
            int i = l - 1;
            int j = r;
            do {
                while (A[++i] < pivot) {}
                while (i < j && pivot < A[--j]) {}
                swap(A, i, j);
            } while (i < j);
            // undo the last swap
            swap(A, i, j);
            // put pivot in place
            swap(A, r, i);
            // load up stack
            if (i - 1 > l) {
                stack[++top] = l;
                stack[++top] = i - 1;
            }
            if (r > i + 1) {
                stack[++top] = i + 1;
                stack[++top] = r;
            }
        }
    }
    

    6、测试

    测试程序

    #include <iostream>
    #include <time.h>
    using namespace std;
    
    int main() {
        const int num = 1000;
        const int minVal = 0;
        const int maxVal = 1000;
        int* arr = new int[num];
        for (int i = 0; i < num; i++)
            arr[i] = rand() % (maxVal - minVal + 1) + minVal;
        
        int* a4b = new int[num];
        int* a4s = new int[num];
        int* a4i = new int[num];
        int* a4m = new int[num];
        int* a4q = new int[num];
    
        int* t = new int[num];
    
        for (int i = 0; i < num; i++) a4b[i] = arr[i];
        for (int i = 0; i < num; i++) a4s[i] = arr[i];
        for (int i = 0; i < num; i++) a4i[i] = arr[i];
        for (int i = 0; i < num; i++) a4m[i] = arr[i];
        for (int i = 0; i < num; i++) a4q[i] = arr[i];
    
        clock_t start, end;
    
        start = clock();
        bubbleSort(a4b, num);
        end = clock();
        cout << "bubbleSort: " << (double)(end-start)/CLOCKS_PER_SEC << endl;
        
        start = clock();
        selectionSort(a4s, num);
        end = clock();
        cout << "selectionSort: " << (double)(end-start)/CLOCKS_PER_SEC << endl;
    
        start = clock();
        insertionSort(a4i, num);
        end = clock();
        cout << "insertionSort: " << (double)(end-start)/CLOCKS_PER_SEC << endl;
    
        start = clock();
        mergeSort(a4m, t, 0, num - 1);
        end = clock();
        cout << "mergeSort: " << (double)(end-start)/CLOCKS_PER_SEC << endl;
    
        start = clock();
        quickSort(a4q, 0, num - 1);
        end = clock();
        cout << "quickSort: " << (double)(end-start)/CLOCKS_PER_SEC << endl;
    
        return 0;
    }
    

    测试结果

    数据规模 1000 10000 100000 1000000 10000000 100000000
    bubble sort 0.003 s 0.355 s 41.414 s / / /
    selection sort 0.001 s 0.123 s 12.151 s / / /
    insertion sort 0.002 s 0.224 s 22.881 s / / /
    merge sort 0 s 0.002 s 0.021 s 0.212 s 2.285 s 24.352 s
    quick sort 0 s 0.002 s 0.017 s 0.175 s 1.826 s 19.498 s

    【 阅读更多数据结构与算法系列文章,请看 数据结构与算法复习

  • 相关阅读:
    第一行代码--笔记(1)
    iOS UITableView深入
    iOS 数据库主键重复,依然可以插入
    UILabel文本高度自适应 不同系统出现问题
    UIlabel上的文字 距上 居左 对齐
    UILabel 自定义字体
    【整理】--VC 编译整理
    【整理】--【内核模块】简单例子,编译加载
    【原创】-- uboot,kennel,fs,rootfs 编译制作
    【原创】-- nfs安装配置及使用,挂载根文件系统
  • 原文地址:https://www.cnblogs.com/wsmrzx/p/12545457.html
Copyright © 2011-2022 走看看