算法之分治学习(快速排序)

馋奶兔 提交于 2020-02-02 03:07:30

整体思路

分支步骤:分解问题
(1)分解:将原问题分解成一系列子问题
(2)解决:递归地解各子问题。若子问题足够小,则直接有解;
(3)合并:将子问题的结果合并成原问题的解
在这里插入图片描述

题目

1、快速排序

(1)题目

就是数组的快速排序啦

(2)代码

package com.lanqiao.vidio;

public class QuickSort {
	public static void main(String[] args) {
		int[] A = {9,6,1,5,8};
		sort(A,0,A.length-1);
		for(int a:A)
		{
			System.out.print(a+" ");
		}
	}
	public static void sort(int[] A,int p,int r)
	{
		if(p<r)
		{
			int q=partition(A,p,r);
			sort(A,p,q-1);
			sort(A,q+1,r);
		}
	}

	private static int partition(int[] A, int p, int r) {
		int pivot = A[p];
		int sp = p+1;
		int bigger = r;
		while(sp<=bigger)
		{
			if(A[sp]<=pivot)
			{
				sp++;
			}else {
				int temp = A[sp];
				A[sp]=A[bigger];
				A[bigger]=temp;
				bigger--;
			}
		}
		int temp = A[p];
		A[p]= A[bigger];
		A[bigger]=temp;
		return bigger;
	}
}

(3)思路

(1)分治法思想
(2)选一个枢轴,找到其相应位置
(3)枢轴左侧有序
(4)枢轴右侧有序
(5)整体有序

(4)找枢轴注意点

(1)确定左右指针sp和bigger,如果sp<pivote,指针前进,否则,bigger与sp元素交换,bigger前进直到sp>bigger比较完成
(2)交换完成后,即找到了枢轴一个在的位置,bigger,右侧都比枢轴元素小,右侧都比枢轴元素大
(3)bigger是当前枢轴所在,返回bigger,,进行左侧进行排序,找枢轴,左侧枢轴定位,右侧排序,直到最终全部有序。
在这里插入图片描述

2、双向扫描 快排

1、代码:

package com.lanqiao.vidio;

public class QuickSort1 {
	public static void main(String[] args) {
		int[] A = {9,5,8,1,6};
		sort(A,0,A.length-1);
		for(int a:A)
		{
			System.out.print(a+" ");
		}
	}

	private static void sort(int[] A, int i, int j) {
		if(i<j) {
			int p = petition(A,i,j);
			sort(A,i,p-1);
			sort(A,p+1,j);
		}
	}

	private static int petition(int[] A, int i, int j) {
		int pivot = A[i];
		int left = i+1;
		int right = j;
		while(left<=right)
		{
			while(left<=right&&A[left]<=pivot) left++;//找到左侧第一个比pivot大的数
			while(left<=right&&A[right]>pivot) right--;//找到右侧第一个小于等于pivot的数
			if(left<right)
			{
				int temp = A[left];
				A[left]=A[right];
				A[right]=temp;
			}
		}
		int temp = A[i];
		A[i]=A[right];
		A[right]=temp;
		return right;
	}
}

2、注意点:

(1)在进入枢轴选择方法之前,先判断i和j的关系,否则可能j已经<0了仍然判断,导致越界。
(2)pivot选择优化:选择最大值+最小值/2

3、奇数偶数分离(奇数在前、偶数在后)

1、题目

将一个数组中所有元素进行分离,使得奇数在前,偶数在后,不必关心大小顺序

2、代码

package com.lanqiao.vidio;

public class jiou {
	public static void main(String[] args) {
		int[] arr = {1,4,2,3,5,8,7};
		merge(arr,0,arr.length-1);
		for(int a:arr)
		{
			System.out.print(a+" ");
		}
	}
	
	private static void merge(int[] arr, int i, int j) {
		int left = i;
		int right = j;
		while(left<right)
		{
			while(left<=right&&arr[left]%2!=0) left++;
			while(left<=right&&arr[right]%2==0) right--;
			if(left<=right) {
				int temp = arr[left];
				arr[left]=arr[right];
				arr[right]=temp;
			}
			
		}
	}
}

3、思路

(1)类似于快排,两个指针分别指向前后,找到第一个奇数、第一个偶数,交换顺序,直到指针交叉

4、注意点

(1)在外层while循环过程中,注意交换之前先判断一下left与right,有可能在最后一次中进行了交叉,再交换就破坏了顺序。

4、找第k大数

1、问题

在一个数组中以较高的效率找出第k大的元素

2、代码

package com.lanqiao.vidio;

public class SelectK {
	public static void main(String[] args) {
		int[] arr = {8,5,4,9,3,6};
		int  a = select(arr,3,0,arr.length-1);
		System.out.println(a);
	}

	private static int select(int[] arr, int k,int i,int j) {
		int p = petition(arr,i,j);
		int pK = p+1;//主元是第几个元素
		
		if(pK>k)
		{
			return select(arr,k,i,p-1);//注意return方法否则继续执行
		}else if(pK<k){
			return select(arr,k-pK,p+1,j);//在新序列中找元素
		}else if(pK==k)
		{
			return arr[p];
		}
		return -1;
	}

	private static int petition(int[] arr, int i, int j) {
		int pivot = arr[i];
		int left = i+1;
		int right = j;
		while(left<=right)
		{
			while(left<=right&&arr[left]<pivot) left++;
			while(left<=right&&arr[right]>pivot) right--;
			if(left<=right)
			{
				Utils.swap(arr, left, right);
			}
		}
		Utils.swap(arr, i, right);
		return right;
	}
}

3、思路

(1)类似于快排,快排每次确定的是枢轴所在位置,所在位置+1即第几大元素,当所找元素大小<枢轴所在位置+1,只在其左侧找,舍弃右侧,>同理

4、注意点

(1)每次找方法注意是return 方法 而不是直接调用方法
(2)在查找枢轴右侧时,在新序列中查找元素时,查找的元素位置与初始不同,是k-pK:k-p+1:就是在新序列中,原来查找的元素时第几位

5、查找数组中数目超过一半的数字

1、思路:

(1)既然是找超过一半的数字。肯定有一个数字的个数超过了总个数的一半,找到有序后中间值即可。
(2)利用确定第k大数的算法,找中间的数字即可

6、寻找最小可用ID

1、题目

在一个数组中,乱序排列(但1,2,3,4应该都有),找出一个数,在数组中没有出现且最小

2、思路

(1)找到中间的元素,看其大小是否=k+1(k:元素下标)
(2)=k+1:左半部分紧密,即元素都存在,舍弃,从其右半部分找
(3)>k+1:有半部分稀疏,即缺少元素,从左半部分找,如此往复,最终确定

7、排序时间复杂度

在这里插入图片描述

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!