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

    常规高速排序

    // 高速排序
     int Partition(int arr[], int lhs, int rhs)
     {
    	 int pivot = arr[rhs]; @1
    	 int i = lhs - 1; @2
    	 int temp;
    	 for (int j = lhs; j <= rhs-1; ++j)
    	 {
    		 if (arr[j] < pivot) @3
    		 {
    			 ++i; @4
    			 temp = arr[i];
    			 arr[i] = arr[j];
    			 arr[j] = temp;
    		 }
    	 }
    	 arr[rhs] = arr[i+1]; @5
    	 arr[i+1] = pivot;
    	 return i+1; @6
     }
    
     void QuickSort(int arr[], int lhs, int rhs)
     {
    	 if (lhs < rhs) @7
    	 {
    		 int q = Partition(arr, lhs, rhs);
    		 QuickSort(arr, lhs, q-1);
    		 QuickSort(arr, q+1, rhs);
    	 }
     }

    高速排序是一种基于分治思想的算法。它不稳定,最坏情况为O(n^2),但实践证明高速排序算法是这么多算法中平均执行时间比較优秀的,也是非常多库函数所採用的算法。比方STL的qsort用的就是高速排序实现的。

    高速排序的核心思想:选出一个主元(pivot),然后以主元为基准划分出两拨,一拨小于主元,一拨大于或等于主元。但在每一拨里,元素的顺序是没有保证的,然后再把子序列继续相同处理,直到最后子序列中剩下一个元素时。不再继续递归,终于排序完毕。

    @1:选择主元。也就是划分的基准。採用最右或是最左都能够。

    @2:i这个变量在整个过程中指向的位置:小于主元的那一拨里的最后一个元素的位置,在非递减排序中(本比如此),小于主元的在左側

    @3:高速排序是不稳定的。@3代码中的(<或是<=)会影响到高速排序的递归树模型。假设用(<)。则j所指向的元素和i指向的元素同样且i不会添加,也不会交换;假设用(<=)。则i会右移而且交换。

    @4:i变量的指向添加,而且后面三行代码交换

    @5:这两行代码是把主元安插在合适的位置,由于主元在最右側。且大于或等于主元的一拨靠右側。所以主元要和右側一拨中的第一个交换(仅适用于非递减排序+最右选为主元)。

    @6:主元的最后位置是在i+1处,此位置为切割的两拨的切割点。

    @7:在递归控制的推断条件中,仅仅有一个元素时停止递归,这一点和归并相似。


    高速排序的优化

    优化1

    // 高速+插入排序
     void Quick_InsertSort(int arr[], int lhs, int rhs)
     {
    	 if (rhs - lhs < 5) @1
    	 {
    		 DirectInsertSort(arr, lhs, rhs);
    	 }else
    	 {
    		 int q = Partition(arr, lhs, rhs);
    		 Quick_InsertSort(arr, lhs, q-1);
    		 Quick_InsertSort(arr, q+1, rhs);
    	 }	 
     }

    @1:当子序列足够小的时候,用直接插入排序要比继续递归下去更合适。至于以多少个子序列元素为准。这个能够任意定,但不能过大。

    这个改进是在每一次递归到足够小时,就就地直接插入排序,然后返回。



    优化2

     void Quick_InsertSort1(int arr[], int lhs, int rhs)
     {
    	 if (rhs - lhs < 3)
    	 {
    		 return ; @1
    	 }else
    	 {
    		 int q = Partition(arr, lhs, rhs);
    		 Quick_InsertSort(arr, lhs, q-1);
    		 Quick_InsertSort(arr, q+1, rhs);
    	 }
     }
     void QuickSort1(int arr[], int lhs, int rhs)
     {
    	 Quick_InsertSort1(arr, lhs, rhs); @2
    	 DirectInsertSort(arr, lhs, rhs);
     }

    这个改进和上个改进相比。有一个优化的地方:当递归到足够小的子序列时。不排序而是直接返回。当调用完递归后,在整个序列上应用直接插入排序。因为递归后序列的有序度已经非常高了,所以这个直接插入排序会非常快。


    优化3

    // 从序列的左,中,右三个元素中取出中值。然后放到最右側。

    // 更科学的选择主元,提高了高速排序的效率 void median3(int arr[], int lhs, int rhs) { // 选择排序的思路找出最小值 int min = lhs; int mid = (lhs + rhs) / 2; if (arr[mid] < arr[min]) { min = mid; } if (arr[rhs] < arr[min]) { min = rhs; } if (min != lhs) { int temp = arr[min]; arr[min] = arr[lhs]; arr[lhs] = temp; } // 以上代码:确定出三个中的最小值,然后放到最左側 // 以下再比較mid和rhs位置的元素,找出三个中的中值 if (mid != rhs && arr[mid] < arr[rhs]) { // 将中值放到最右側 int temp = arr[mid]; arr[mid] = arr[rhs]; arr[rhs] = temp; }else { // 在次分支内,最右側本来就是中值 } } // 一趟划分。採用三者取中值作主元 int Partition1(int arr[], int lhs, int rhs) { median3(arr, lhs, rhs); @1 int pivot = arr[rhs]; @2 int i = lhs; int j = rhs - 1; while (1) @3 { while (i < j && arr[i] < pivot) @4 { ++i; } while (i < j && pivot < arr[j]) @5 { --j; } if (i < j) @6 { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp;

    			 ++i; --j;
    		 }else
    		 {
    			 break; @7
    		 }
    	 }
    	 if (arr[i] > pivot) @8
    	 {
    		 arr[rhs] = arr[i];
    		 arr[i] = pivot;
    	 }
    	 return i; @9
     }

    这个partition函数的思路:从左右两側往中间并行推进。i左側是小于主元的区间。j右側是大于或等于主元的区间。i和j之间的是还未被处理的区间。

    @1:先调用median3函数。取左。中。右三个值的中值,并把其放到数组的最右边。

    更科学的选取主元

    @2:选取主元

    @3:最外层循环使用死循环,在整个循环中,i和j满足某个条件会跳出循环

    @4:i从左到右。遇到比主元小的直接continue,直到遇到一个比主元大的(或是i和j相遇),跳出小循环

    @5:j从右到左。遇到比主元大于或等于的直接continue,直到遇到一个小于主元的(或是i和j相遇),跳出小循环

    @6:当两个小循环都结束后,i指向一个大于主元的。j指向一个大于或等于主元的,然后i和j所指位置的元素互换,然后i和j分别移动一个位置

    @7:假设(i < j)不成立。则一定是i和j相遇,那么一趟划分结束

    @8:最后相遇的位置i或j就是切割点,假设这个点的元素比主元大(一般都要大。除非相等),交换。

    @9:最后把切割点返回


  • 相关阅读:
    Linux centosVMware Linux监控平台介绍、zabbix监控介绍、安装zabbix、忘记Admin密码如何做
    Linux centosVMware Linux集群架构LVS DR模式搭建、keepalived + LVS
    Linux centosVMware 集群介绍、keepalived介绍、用keepalived配置高可用集群
    Linux centosVMware 配置Tomcat监听80端口、配置Tomcat虚拟主机、Tomcat日志
    Linux centosVMware Tomcat介绍、安装jdk、安装Tomcat
    Linux centosVMware xshell使用xftp传输文件、使用pure-ftpd搭建ftp服务
    Linux centosVMware NFS介绍、NFS服务端安装配置、NFS配置选项
    Linux centosVMware NFS exportfs命令、NFS客户端问题、FTP介绍、使用vsftpd搭建ftp
    Linux centosVMware mysql用户管理、常用sql语句、mysql数据库备份恢复
    Linux centosVMware MySQL常用操作设置更改root密码、连接mysql、mysql常用命令
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/5184036.html
Copyright © 2011-2022 走看看