快排变种

随机化快排

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

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

平衡快排(Balanced Quicksort)

每次尽可能地选择一个能够代表中值的元素作为关键数据,然后遵循普通快排的原则进行比较、替换和递归。通常来说,选择这个数据的方法是取开头、结尾、中间3个数据,通过比较选出其中的中值。取这3个值的好处是在实际问题中,出现近似顺序数据或逆序数据的概率较大,此时中间数据必然成为中值,而也是事实上的近似中值。万一遇到正好中间大两边小(或反之)的数据,取的值都接近最值,那么由于至少能将两部分分开,实际效率也会有2倍左右的增加,而且利于将数据略微打乱,破坏退化的结构。

外部快排(External Quicksort)

与普通快排不同的是,关键数据是一段buffer,首先将之前和之后的M/2个元素读入buffer并对该buffer中的这些元素进行排序,然后从被排序数组的开头(或者结尾)读入下一个元素,假如这个元素小于buffer中最小的元素,把它写到最开头的空位上;假如这个元素大于buffer中最大的元素,则写到最后的空位上;否则把buffer中最大或者最小的元素写入数组,并把这个元素放在buffer里。保持最大值低于这些关键数据,最小值高于这些关键数据,从而避免对已经有序的中间的数据进行重排。完成后,数组的中间空位必然空出,把这个buffer写入数组中间空位。然后递归地对外部更小的部分,循环地对其他部分进行排序。

三路基数快排

Three-way Radix Quicksort,也称作Multikey Quicksort、Multi-key Quicksort):结合了基数排序(radix sort,如一般的字符串比较排序就是基数排序)和快排的特点,是字符串排序中比较高效的算法。该算法被排序数组的元素具有一个特点,即multikey,如一个字符串,每个字母可以看作是一个key。算法每次在被排序数组中任意选择一个元素作为关键数据,首先仅考虑这个元素的第一个key(字母),然后把其他元素通过key的比较分成小于、等于、大于关键数据的三个部分。然后递归地基于这一个key位置对“小于”和“大于”部分进行排序,基于下一个key对“等于”部分进行排序。

时间: 2024-12-15 06:41:15

快排变种的相关文章

初探快排

学了数据结构,实现下快排, public void QuickSort1(float[] seq,int low,int hight){int i = low;//记录最左值索引int j = hight;//记录最右值索引float temp = seq[low];//记录比较值(此处是最左值)while (low < hight)//每轮比较{while (low < hight && temp >= seq[hight]){hight--;}seq[low] = s

算法学习——单链表快排

/**  * 以p为轴对start-end间的节点进行快排(包括start && 不包括end):  * 思路:  * 1.将头节点作为轴节点start,从start.next开始遍历,如果节点小于轴start的值,将该节点插入到轴节点后面:  * 2.将轴节点插入合适位置,即找到最后一个小于轴的节点,将该节点与轴节点值互换,此时就链表分为两部分,小于轴节点和大于轴节点:  * 3.递归的遍历2中两部分节点.  *   * @param p  * @param start  * @para

快排的递归和非递归

常用的快排都是用递归写的,因为比较简单,但是可以用栈来实现非递归的快排. 第一种是递归的快排 #include<stdio.h> #include <stdlib.h> #include <time.h> int quick(int a[],int i ,int j) {     int tmp=0,key,b=0;     int im,jm;     im=i;     jm=j;     key=a[i];     if(i>j)         retur

快排,随机快排,双路快排,三路快排的理解

再讲快排之前,首先对于任何一个数组,无论之前是多么杂乱,排完之后是不是一定存在一个数作为分界点(也就是所谓的支点),在支点左边全是小于等于这个支点的,然后在这个支点右边的全是大于等于这个支点的,快排过程就是寻找这个支点过程 先看普通的快排(普通单路快排) 代码如下 let findIndex = (arr, l, len) => { let par = arr[l], j = l for (let i = l + 1; i <= len; i++) { if (arr[i] < par)

Quick Sort(快排)

这是挖坑填补法的演示 快排之挖坑填补法: 1 void Quick(int top/*起始位置*/,int end/*末尾位置*/,int arr[])//挖坑填补法 2 { 3 int i=top,j=end,mark;//i是记住前面的坑 j记住后面的坑 mark记住标准值 4 5 mark=arr[top];//以起始位置作为标准值,同时起始点成为第一个坑 6 if(top>=end)return; 7 while(i<j) 8 { 9 while(i<j)//从后向前找比标准值小

冒泡,快排代码+注释

冒泡: package Sort; public class BubbleSort { public static void main(String[] args) { int[] list = new int[]{12,14,3,24,1,33}; int[] nums = bubbleSort(list); for(int i = 0;i< list.length;i++){ System.out.println(nums[i]); } } public static int[] bubbl

C++ 快排

// 进行一轮快排并返回当前的中间数 int getMiddle( int* arr, int low, int high ) { auto swaparr = [&]( int i, int j ) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; }; if( high - low > 0 ) { int k = arr[low], i = low, j = high; while( i != j ) { //R->L for(

python 冒泡和快排,不多说【无聊】

1 #-*-coding:utf8-*- 2 import random 3 a=[] 4 b=[] 5 def init_array(): 6 for i in range(10000): 7 v = random.randint(1,10000) 8 a.append(v) 9 b.append(v) 10 11 #冒泡 12 def sort_array(a): 13 for i in range(len(a)): 14 for j in range(i+1,len(a)): 15 if

快排的第4个参数

问题描述 我想写个能够排序多种类型的函数.   当我着手排序字符串时,  发现直接把strcmp传递给qsort后, 无法正常排序. 解决方法 我注意到strcmp的参数与快排第4个参数的形参并不一致.  我便自己写了个比较函数, 问题solved! 附上 1 /* 2 ** 比较两个字符串 3 */ 4 int str_cmp ( void const *p1, void const *p2 ) 5 { 6 char *str1; 7 char *str2; 8 9 str1 = *(char