算法导论7.3快速排序的随机化版本

以下摘自网络

随机化快排:快速排序的最坏情况基于每次划分对主元的选择。基本的快速排序选取第一个元素作为主元。这样在数组已经有序的情况下,每次划分将得到最坏的结果。一种比较常见的优化方法是随机化算法,即随机选取一个元素作为主元。这种情况下虽然最坏情况仍然是O(n^2),但最坏情况不再依赖于输入数据,而是由于随机函数取值不佳。实际上,随机化快速排序得到理论最坏情况的可能性仅为1/(2^n)。所以随机化快速排序可以对于绝大多数输入数据达到O(nlogn)的期望时间复杂度。一位前辈做出了一个精辟的总结:“随机化快速排序可以满足一个人一辈子的人品需求。”

  随机化快速排序的唯一缺点在于,一旦输入数据中有很多的相同数据,随机化的效果将直接减弱。对于极限情况,即对于n个相同的数排序,随机化快速排序的时间复杂度将毫无疑问的降低到O(n^2)。解决方法是用一种方法进行扫描,使没有交换的情况下主元保留在原位置。

以上摘自网络

#include <stdint.h>
#include <iostream>
#include <time.h>
#ifdef __linux
#include <stdlib.h>
#include <stdio.h>
#endif

// RANDOMIZED-QUICKSORT(A, p, r)
// if p < r
//     q = PARTITION(A, p, r)
//     RANDOMIZED-QUICKSORT(A, p, q - 1)
//     RANDOMIZED-QUICKSORT(A, q + 1, r)
// To sort an entire array, the initial call is RANDOMIZED-QUICKSORT(A, 1, A.length)

// PARTITION(A, p, r)
// x = A[r]
// i = p - 1
// for j = p to r - 1
//     if A[j] <= x
//         i = i + 1
//         exchange A[i + 1] with A[r]
// exchange a[i + 1] with A[r]
// return i + 1

// RANDOMIZED-PARTITION
// i = RANDOM(p, r)
// exchangeA[r] with A[i]
// return PARTITION(A, p, r)

void swap(int64_t* A, uint64_t i, uint64_t j)
{
    int64_t tmp = A[i];
    A[i] = A[j];
    A[j] = tmp;
}

int64_t partition(int64_t* A, int64_t p, int64_t r)
{
    int64_t x = A[r];
    int64_t i = p;
    for (int64_t j = p; j < r; j++)
    {
        if (A[j] <= x)
        {
            swap(A, i, j);
            i++;
        }
    }
    swap(A, i, r);
    return i;
}

int64_t RandomizedPartition(int64_t* A, int64_t p, int64_t r)
{
    int64_t i = (rand() % (r - p)) + p/* + 1*/;
    swap(A, i, r);
    return partition(A, p, r);
}

void RandomQuicksort(int64_t* A, int64_t p, int64_t r)
{
    if (p < r)
    {
        int64_t q = RandomizedPartition(A, p, r);
        RandomQuicksort(A, p, q - 1);
        RandomQuicksort(A, q + 1, r);
    }
}

void print_array(int64_t* A, int64_t n)
{
    std::cout << "print array" << std::endl;
    for (int64_t i = 0; i < n; i++)
    {
        std::cout << A[i] << " ";
    }
    std::cout << std::endl;
}

int main()
{
    srand((int)time(0));

    int64_t array[] = { 2, 8, 7, 1, 3, 5, 6, 4 };
    print_array(array, 8);
    RandomQuicksort(array, 0, 7);
    print_array(array, 8);
    getchar();
    return 0;
}

时间: 2024-10-17 06:16:10

算法导论7.3快速排序的随机化版本的相关文章

排序算法之快速排序的随机化版本

4.3 快速排序的随机化版本 这种方法并不是一种全新的排序算法,而是在快速排序的基础上加入随机化的因素,因素,因而仍然将其作为第四种方法(快速排序)的一种补充. 为什么要提出快速排序的随机化版本,主要是对于快速排序法其划分情况的好坏会直接影响排序的效率,而且,快速排序的平均性能较好,所以,加入随机化成分,可以使该算法对于所有输入均能获得较好的平均情况性能. 针对加入随机化的环节,选取的是选取主元的环节,因为主元的选取直接影响快速排序算法的数组划分. C代码实现为: #include <stdio

算法导论——lec 07 快速排序

一. 快速排序的描述 1. 快速排序是一种原地排序的算法,最坏情况下的时间复杂度为Θ(n^2),期望的运行时间为Θ(n logn),且其中隐含的常数因子较小. 2. 快速排序分三个步骤: 分解:数组A[p...r]被划分成两个数组A[p...q-1]和A[q+1...r],使得A[p...q-1]中的元素都小于等于A[q],A[q+1...r]中的元素都大于等于A[q].下标q在这个划分过程中计算. 解决:递归调用快速排序,对子数组A[p...q-1]和A[q+1...r]进行排序. 合并:两个

复习数据结构:排序算法(五)——快速排序的各种版本

之前已经比较熟悉快排的基本思想了,其实现的方式也有很多种.下面我们罗列一些常见的实现方式: 版本一:算法导论上的单向扫描,选取最后一个元素作为主元 #include<iostream> using namespace std; int partition(int data[], int low, int high) { int pivot = data[high]; // let the last atom be the pivot int i = low - 1; // mark the p

算法导论4:快速排序 2016.1.4

今天上最后一节史纲课,老师说不管什么学科,最重要的就是思想.我觉得很有道理. 好吧,不扯了.原谅我看书选择了速读策略,中间有很多感觉目前还很难看懂,以后有时间再细细学习.把略过去的在这里记一下. 一.矩阵乘法算法.复杂度从n^3优化到了n^2.81 (数字比较神奇).因为还没学线性代数,所以以后学了再看. 二.递归复杂度的计算和估计.这部分看起来有些复杂,好像需要比较高的数学水平,有空研究一下. 三.堆排序.这个以前已经写过了.http://www.cnblogs.com/itlqs/p/475

快速排序的随机化版本

#include<iostream> #include<ctime> using namespace std; void swap(int*a, int *b) { int *c = a; a = b; b = c; } int Partition(int *A, int p, int r) { int x = A[r]; int i = p - 1; for (int j = p; j < r; j++) { if (A[j] < x) { i++; swap(A[i

《算法导论》 — Chapter 7 快速排序

序 快速排序(QuickSort)也是一种排序算法,对包含n个数组的输入数组,最坏情况运行时间为O(n^2).虽然这个最坏情况运行时间比较差,但是快速排序通常是用于排序的最佳实用选择,这是因为其平均性能相当好,期望的运行时间为O(nlgn),且O(nlgn)中隐含的常数因子很小,另外它还能够进行就地排序在虚拟环境中也能很好的工作. 原理 快速排序也和合并排序一样,基于分治法,分为分解.解决.合并三个步骤: 分解:数组array[low-high]被分为两个(可能空)子数组array[low-te

【算法导论】学习笔记——第7章 快速排序

对于包含n个数的输入数组来说,快速排序是一种最坏情况时间复杂度为theta(n^2)的排序算法.虽然最坏情况时间复杂度很差,但是快速排序通常是实际排序应用中最好的选择,因为它的平均性能非常好,期望时间复杂度是theta(nlgn),而且常数因子非常小,并可进行原址排序.1. 快速排序的描述快速排序可采用分治思想实现.分解:数组A[p..r]被划分为两个(可能为空)子数组A[p..q-1]和A[q+1..r],使得A[p..q-1]中的每一个元素都小于等于A[q],而A[q]也小于等于A[q+1.

算法导论(2)快速排序

一.一般的快速排序 QuickSort.h文件 #pragma once /*交换两个数*/ template<class T> void Swamp(T &a, T &b) { T temp; temp = a; a = b; b = temp; } /* 将数组分为小于等于x,和大于x的两个部分 其中这里x选择为数组的最后一个元素 如当输入{ 2,8,7,1,3,5,6,4 }时,输出为{2,1,3,4,7,5,6,8},函数返回值为3,即数组中x的索引 */ templa

《算法导论》读书笔记(三)

本章介绍了快速排序及其算法分析,快速排序采用的是分治算法思想,对包含n个数的输入数组,最坏情况下运行时间为θ(n^2),但是平均性能相当好,期望的运行时间为θ(nlgn).另外快速排序能够就地排序(我理解是不需要引入额外的辅助空间,每次划分能确定一个元素的具体位置),在虚拟环境中能很好的工作. 1.快速排序的描述 快速排序算法采用的分治算法,因此对一个子数组A[p-r]进行快速排序的三个步骤为: (1)分解:数组A[p...r]被划分为两个(可能为空)子数组A[p...q-1]和A[q+1...