分治法-基于分之策略的归并排序和快速排序

来源:互联网 发布:青岛淘宝运营培训机构 编辑:程序博客网 时间:2024/06/06 12:26
分治法
分治法在算法结构上是递归的.为了解决一个给定的问题,算法一次或多次递归调用其本身以解决紧密相关的若干子问题.
思想:
将原问题分解为几个规模较小但类似有原问题的子问题,递归地求解这些子问题,然后再合并这些子问题的解来建立原有问题的解.
分治法每层递归的步骤:
1.分解原问题为若干子问题,这些子问题是原问题的规模较小的实例.
2.解决这些子问题,递归的求解各子问题.如果子问题的规模足够小,则直接求解.

3.合并这些子问题的解构成原问题的解.

1.基于分之策略的归并排序:

不断的将一个数组从中间分为两部分,直到其成为单个数字,在对其进行归并,最后得到一个有序数组.

public class MergeSort {public static void main(String[] args) {int[] arr = { 21, 34, 46, 243, 54654, 3, 43, 564, 253, 54, 345, 0, 654,343, 23, 89 };merge_sort(arr, 0, arr.length - 1);for (int cnt : arr) {System.out.print(cnt + " ");}}//递归分解private static void merge_sort(int[] arr, int low, int high) {if (low < high) {int center = (low + high) / 2;merge_sort(arr, low, center);merge_sort(arr, center + 1, high);merge(arr, low, center, high);}}// 拆分数组private static void merge(int[] arr, int low, int center, int high) {int lowLength = center - low + 1; // 计算上半部分数组的长度int highLength = high - center; // 计算下半部分数组的长度int[] lowArray = new int[lowLength + 1];// 设置数组长度+1,将多余的一个设置为哨兵,便于归并排序int[] highArray = new int[highLength + 1];for (int i = low; i <= center; i++) {// 将上半部分数组赋值个给lowArraylowArray[i - low] = arr[i];}for (int i = center + 1; i <= high; i++) {// 将下半部分数组赋值个给highArrayhighArray[i - center - 1] = arr[i];}mergeArray(arr, lowArray, highArray, low, high);}// 合并数组private static void mergeArray(int[] arr, int[] lowArray, int[] highArray,int low, int high) {lowArray[lowArray.length - 1] = Integer.MAX_VALUE;// 哨兵highArray[highArray.length - 1] = Integer.MAX_VALUE;int indexLow = 0;// 表示lowArray数组下标int indexHigh = 0;// 表示highArray数组下标for (int i = low; i <= high; i++) {// 归并if (lowArray[indexLow] <= highArray[indexHigh]) {arr[i] = lowArray[indexLow];indexLow++;} else {arr[i] = highArray[indexHigh];indexHigh++;}}}}

2.基与分之策略的快速排序

快速排序的思想:

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,
  然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列.
  步骤:
  设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,
  然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。快速排序不是
  一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
  一趟快速排序的步骤是:
  1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
  2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
  3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换;
  4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
  5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,
  4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,
  进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。

public class PartitionQuickSort {public static void main(String[] args) {int[] arr = {1,234,345,2,2422,42,1,432,4232,5,4,64,756,6,8,6,86,46,56};quickSort(arr,0,arr.length-1);for(int i:arr){System.out.print(i + " ");}}//递归调用private static void quickSort(int[] arr, int low, int high) {if(low < high){int p = getPoint(arr,low,high);quickSort(arr, p+1, high);quickSort(arr, low, p-1);}}//获取哨兵在这个有序队列中的位置private static int getPoint(int[] arr, int low, int high) {int var = arr[low];while(low < high){while(low < high && arr[high] >= var){high--;}swap(arr,low,high);while(low < high && arr[low] < var){low ++;}swap(arr,low,high);}return low;}//交换数组中两个数private static void swap(int[] arr, int low, int high) {int temp = arr[low];arr[low] = arr[high];arr[high] = temp;}}

3.数组中的最大连续子序列

对于一个数组,求它最大的连续子序列.例如在数组{1,5,-3,4,-5}这个数组中最大连续子序列为{1,5,-3,4}和为7.

对于一个数组,它的最大连续子序列可分为三种情况:在上半部分,在下半部分,跨过中间位置包含上半部分和下半部分.

/* * 求数组中的最大连续子序列 *///定义一个类用来存储结果class Result {int sum;// 记录字序列的和int low;// 记录子序列的下界int high;// 记录子序列的上界}public class FindMaxSubarray {// 包含中间位置的最大子序列public static Result findMaxCrossSubarray(int[] arr, int low, int mid,int high) {Result re = new Result();int leftsum = Integer.MIN_VALUE; // 设定最小值int maxleft = 0;int maxright = 0;int sum = 0;for (int i = mid; i >= low; i--) {// 从中间位置开始往前求最大序列sum = sum + arr[i];if (sum > leftsum) {leftsum = sum;maxleft = i;}}int rightsum = Integer.MIN_VALUE; // 设定最小值sum = 0;for (int i = mid + 1; i <= high; i++) {// 从中间位置开始往后求最大序列sum = sum + arr[i];if (sum > rightsum) {rightsum = sum;maxright = i;}}re.low = maxleft;re.high = maxright;re.sum = leftsum + rightsum;// 得到包含中间位置的最大子序列return re;}public static Result findMaxSubarray(int[] arr, int low, int high) {if (high == low) {// 递归出口Result re = new Result();re.low = low;re.high = high;re.sum = arr[low];return re;} else {int mid = (low + high) / 2;Result ResultLeft = findMaxSubarray(arr, low, mid);Result ResultRight = findMaxSubarray(arr, mid + 1, high);Result ResultCross = findMaxCrossSubarray(arr, low, mid, high);if (ResultLeft.sum >= ResultRight.sum&& ResultLeft.sum >= ResultCross.sum) {return ResultLeft;// 返回最大的值所在的对象} else if (ResultRight.sum >= ResultLeft.sum&& ResultRight.sum >= ResultCross.sum) {return ResultRight;// 返回最大的值所在的对象} elsereturn ResultCross;// 返回最大的值所在的对象}}public static void main(String[] args) {int[] arr = { 13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22,15, -4, 7 };// int[] arr ={-1,-2,-3,-4};Result re = new Result();re = findMaxSubarray(arr, 0, arr.length - 1);System.out.println(re.sum + " " + re.low + " " + re.high);}}


原创粉丝点击