序列的划分

来源:互联网 发布:lol引燃伤害数据 编辑:程序博客网 时间:2024/05/17 02:14

1 算法描述与分析

(1)问题的理解与描述

序列的划分问题描述如下:

输入:序列A[p...r]

输出:下标q(p≤q≤r),原序列A[p...r]的一个重排:使得A[p...q]中的元素值不超过A[q](=原A[r]的值),A[q+1...r]中的元素值均大于A[q]。

解决此问题的算法对序列A[p...r]进行原地重组。算法选择元素x=A[r]作为主元素,以它为分界点对序列A[p...r]进行划分,目标是将其分成前后两段A[p...q]和A[q+1...r],使得A[p...q]中的元素值不超过x,而A[q+1...r]中的元素值大于x。 算法维护两个下标值i和j,初始值分别为p-1和p。让j在[p...r]中扫描,若A[j]≤A[r],则将A[j]与A[i+1]交换,然后i增加1。这样,在此过程中,A[p...i]中的元素均不超过A[r],而A[i+1...j]中的元素大于A[r]。随着j的增加,A[p...i]和A[i+1...j]也随之增长,最后j达到r-1,并将A[r+1]和A[r]交换,返回i+1即为所求的q。

例如对下图中所示的序列进行的操作:


图:对一个样本序列的划分操作。浅蓝色数组元素都在第一部分A[p...i]中,其值都不大于x。深蓝色数组元素都在第二部分A[i+1,j]中,其值都大于x。无阴影元素是尚未进入上述两个部分的元素,黑色元素是基准元素。(a)初始的序列和变量设置。没有任何元素进入两部分。(b)~(h)表示第3~6行的For循环的每一次重复。黑色双向箭头表示第6行的元素交换操作。(i)表示上述循环终止后第7行执行的元素交换操作。  

(2)算法的伪代码描述

PARTITION(A, p, r)1  x ← A[r]2  i ← p - 13  for j ← p to r -14      do if A[j] ≤ x 5          then i  ← i + 16              exchange A[i] ←→ A[j]7  exchange A[i+1] ←→ A[r]8  return i + 1
算法:解决划分问题的PARTITION算法

(3)算法的正确性

(4)算法的运行时间

假定序列A[p...r]中含有n个元素。在此过程中,第3~6行的for循环重复了n次,所以该算法的最坏运行时间为O(n)。

2 程序实现

       /** * @MethodName:partition * @Description: 该方法用于序列的划分* @param a 用于存储序列的数组* @param p 序列划分的开始位置* @param r 序列划分的结束位置* @return 序列划分的分界点*/public static int partition(int []a, int p, int r){int x = a[r];//设定基准元素为a[r]int i = p - 1;//用于记录序列前一部分的最后一个元素位置,初始为p-1int j = p;//用于循环扫描序列,范围为p~r-1//循环扫描序列for(j = p;j < r; j++ ){//如果在p~r-1中找到某一个元素比基准元素小,则将其交换至第一部分尾部,//对应元素交换至j处if(a[j]<=x){//由于第一部分即将新添加一个元素a[j],所以i加1(为a[j]要交换至的位置)i++;//交换j和i处元素swap(a, j, i);}}//最后交换基准元素a[r]至第一部分尾部swap(a, i+1, r);//返回序列划分的分界点位置i+1return i+1;}/** * @MethodName:swap * @Description: 用于交换序列中两个位置的元素* @param a 用于存储序列的数组* @param p 要交换的第一个元素的位置* @param r 要交换的第二个元素的位置*/private static void swap(int []a, int p, int r){int t = a[p];a[p] = a[r];a[r] = t;}


0 0