zoukankan      html  css  js  c++  java
  • 快速排序

    一、算法导论上的快速排序

    void swap(int* value1, int* value2)
    {
        int temp = *value1;
        *value1 = *value2;
        *value2 = temp;
    }
    void QuickSort(int* array, int low, int high)
    {
        if (low >= high) return;
    
        int i = low - 1;
        for (int j = low; j < high; ++j) {
            if (array[j] < array[high]) {
                ++i;
                swap(&array[i], &array[j]);
            }
        }
    
        int pivot = i + 1;
        swap(&array[pivot], &array[high]);
    
        QuickSort(array, low, pivot - 1);
        QuickSort(array, pivot + 1, high);
    }

          上述将一次快速排序的过程直接写在快速排序中,减少递归时调用函数的次数,提高效率。

    非递归形式:

    int Partition(int* array, int low, int high)
    {//a trip quicksort
        int i = low - 1;
        for (int j = low; j < high; ++j) {
            if (array[j] < array[high]) {
                ++i;
                swap(&array[i], &array[j]);
            }
        }
    
        int pivot = i + 1;
        swap(&array[pivot], &array[high]);
    
        return pivot;
    }
    
    void QuickSort(int* array, int low, int high)
    {
        //stack initilization
        int stack[200] = {0};
        int top = 0;
    
        stack[top] = low;
        ++top;
        stack[top] = high;
        ++top;
    
        int start = 0;
        int end = 0;
        int pivot = 0;
        while (top) {
            start = stack[top];
            --top;
            end = stack[top];
            --top;
    
            pivot = Partition(array, start, end);
    
            if (start < pivot - 1) {
                stack[top] = start;
                ++top;
                stack[top] = pivot - 1;
                ++top;
            }
    
            if (pivot + 1 < end) {
                stack[top] = pivot + 1;
                ++top;
                stack[top] = end;
                ++top;
            }
        }
    }

          递归算法使用的栈由程序自动产生,栈中包含:函数调用时的参数和函数中的局部变量。如果局部变量很多或者函数内部又调用了其他函数,则栈会很大。每次递归 调用都要操作很大的栈,效率自然会下降。而对于非递归算法,每次循环使用自己预先创建的栈,因此不管程序复杂度如何,都不会影响程序效率。一般情况下,同一个问题,非递归总比递归效率高。 

    二、Hoare及其变种版本的快速排序

    Hoare版本:

    void QuickSort(int* array, int low, int high)
    {
        if (low >= high) return;
    
        int key = array[low];//pivot
        int i = low;
        int j = high;
        while (i < j) {
            while (array[j] >= key && i < j) {
                --j;
            }
            while (array[i] <= key && i < j) {
                ++i;
            }
            if (i < j) {
                swap(&array[i], &array[j]);
            }
        }
        swap(&array[low], &array[i]);
    
        QuickSort(array, low, i - 1);
        QuickSort(array, i + 1, high);
    }

    Hoare变种版本:

    void QuickSort(int* array, int low, int high)
    {
        if (low >= high) return;
    
        int key = array[low];
        int i = low;
        int j = high;
        while (i < j) {
            while (array[j] >= key && i < j) {
                --j;
            }
            if (i < j) {
                array[i] = array[j];
            }
    
            while (array[i] <= key && i < j) {
                ++i;
            }
            if (i < j) {
                array[j] = array[i];
            }
        }
        array[i] = key;
        
        QuickSort(array, low, i - 1);
        QuickSort(array, i + 1, high);
    }

          该变种版本与算法导论版本比较:

    ①算法导论版本中使用swap来交换数据,而在Hoare变种版本中使用的是赋值的方式,其实这两种方式的效率没有多大差别。

    ②变种版本swap之后还要原地判断一次,但是算法导论版本不用。

    ③ 另外,小于等于的效率和小于的效率也是差不多的。 

    三、随机化快速排序

        快速排序在最坏情况下,时间复杂度为O(n^2),这和主元的选择有关,通过随机化选择主元,减少最坏情况的发生。

    递归形式:

    void RandomizedQuickSort(int* array, int low, int high)
    {
        if (low >= high) return;
    
        //select pivot randomly
        int pivot = 0;
        srand(time(0));
        pivot = low + rand()%(high - low + 1);
        swap(&array[pivot], &array[high]);
    
        int i = low - 1;
        for (int j = low; j < high; ++j) {
            if (array[j] < array[high]) {
                ++i;
                swap(&array[i], &array[j]);
            }
        }
    
        pivot = i + 1;
        swap(&array[pivot], &array[high]);
    
        QuickSort(array, low, pivot - 1);
        QuickSort(array, pivot + 1, high);
    }

    非递归形式:

    int Partition(int* array, int low, int high)
    {//a trip quicksort
        int i = low - 1;
        for (int j = low; j < high; ++j) {
            if (array[j] < array[high]) {
                ++i;
                swap(&array[i], &array[j]);
            }
        }
    
        int pivot = i + 1;
        swap(&array[pivot], &array[high]);
    
        return pivot;
    }
    
    void RandomizedQuickSort(int* array, int low, int high)
    {
        //stack initilization
        int stack[200] = {0};
        int top = 0;
    
        stack[top] = low;
        ++top;
        stack[top] = high;
        ++top;
    
        int start = 0;
        int end = 0;
        int pivot = 0;
        while (top) {
            start = stack[top];
            --top;
            end = stack[top];
            --top;
         //select pivot randomly srand(time(
    0)); pivot = start + rand()%(end - start + 1); swap(&array[pivot], &array[end]); pivot = Partition(array, start, end); if (start < pivot - 1) { stack[top] = start; ++top; stack[top] = pivot - 1; ++top; } if (pivot + 1 < end) { stack[top] = pivot + 1; ++top; stack[top] = end; ++top; } } }

     

    四、平衡快速排序

    选取头,尾,中间三个元素中中间值的元素来作为主元。每趟排序执行前,加入以下代码:

        int mid = low + (high - low) / 2;//preventing overflow
    
        if (array[low] < array[mid]) {
            swap(&array[low], &array[mid]);
        }
        
        if (array[mid] < array[high] {
            swap(&array[mid], &array[high]);
        }
        
        if (array[high] < array[low]) {
            swap(&array[high], &array[low]);
        }
    
        int key = array[low];//pivot

     

    五、随意位置的主元

         有两种方法:

    1、将主元交换至数组头或者尾,再用算法导论版本或者Hoare版本的快速排序

    2、代码如下:

    void QuickSort(int* array, int low, int high)
    {
        if (low >= high) return;
    
        int i = low;
        int j = high;
        int key = array[low + (high - low) / 2];
    
        //  partition
        while (i <= j) {
            while (array[j] > key) j--;
            while (array[i] < key) i++;
    
            if (i <= j) {
                swap(&array[i], &array[j]);
                i++;
                j--;
            }
        }
    
        //  recursion
        QuickSort(array, low, j);
        QuickSort(array, i, high);
    }

     六、链表排序

    递归:

    Node* QuickSort(Node* head, Node* tail)
    {//this algorithm separate the the linkedlist into two parts based on quicksort
     //one is less than the pivot, while the other part is no less than the pivot
        if (head->next == tail || head->next->next == tail) return head;
    
        Node* pivot = head->next;
        Node* current = pivot->next;
    
        Node* less_than_pivot = head;
        Node* more_than_pivot = pivot;
    
        while (current != tail) {
            if (current->data < pivot->data) {
                less_than_pivot->next = current;
                less_than_pivot = current;
            } else {
                more_than_pivot->next = current;
                more_than_pivot = current;
            }
            current = current->next;
        }
        less_than_pivot->next = pivot;
        more_than_pivot->next = tail;
    
        QuickSort(head, pivot);
        QuickSort(pivot, tail);
    
        return head;
    }

     非递归:

    链表的快排非递归实现与数组的相差不多,也是利用栈来完成的,这里就不给出了。

  • 相关阅读:
    _mysql.c(42) : fatal error C1083: Cannot open include file: 'config-win.h':问题的解决
    pycharm 插件的升级
    机器学习
    Python三大神器
    印记中文
    Emacs, Nano, or Vim 编辑器“三剑客”
    码云-中国的github
    代码质量管控的四个阶段
    <<创新之路>> 纪录片观后感
    API (Application Programming Interface) 文档大全
  • 原文地址:https://www.cnblogs.com/wolves-dave/p/3305305.html
Copyright © 2011-2022 走看看