快速排序

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

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;
}

 非递归:

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

原文地址:https://www.cnblogs.com/wolves-dave/p/3305305.html