关于分治算法的个人理解

关于分治算法的个人理解:
把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。
以快速排序为例,先取一个参数。将大于该参数的值放在右边,小于该参数的值放在左边,使该参数处于最正确的位置上。
该案例的基本思想:是将该数组排序问题分成为该数组中的数值与选取的参数值比较大小。即简单的一对一的比较问题。
该比较问题相互独立、具有最优子结构性质,且可以合并。

1.快速排序

public class Test{

public static void main(String []args){

int arr[] = {40,30,15,57,86,68,98};

quick(arr , 0 , arr.length-1);

for(int i:arr){
System.out.print(i+" ");
}

}

public static void quick(int[] arr , int min , int max){

if(min < max){

int n = sort(arr , min , max);

quick(arr , min , n-1);
quick(arr , n+1 , max);

}

}

public static int sort(int[] arr , int min , int max){

int sum = arr[min];

while(min < max){

while(min < max && arr[max] >= sum){

max--;

}

arr[min] = arr[max];

while(min < max && arr[min] <= sum){

min++;

}

arr[max] = arr[min];

}

arr[min] = sum;

return min;

}

}

二分搜索:
public class Test{

public static void main(String []args){

int []arr = {0,1,3,5,7,8,9};

System.out.println(select(arr,0,arr.length-1,3));
}

public static int select(int[] arr , int min , int max , int i){

while(min <= max){

int middle = (min + max)/2;

if(i == arr[middle]){
return middle;
}else if(i<arr[middle]){
return select(arr,min,middle - 1,i);
}else{
return select(arr,middle + 1,max,i);
}
}
return -1;
}

}

汉诺塔:

public class Test {

public static void main(String []args){

move(3,"A","B","C");
}

public static void move(i,String A, Sting B, String C){

if(i==1){
System.out.println("把"+i+"从"+A+"移动到"+C);
}else{

move(i-1,A,C,B);
System.out.println("把"+i+"从"+A+"移动到"+C);
move(i-1,B,A,C);
}
}
}

矩阵相加:

public class Test{

public static void main(String []args){

int[][] a = {{1,2},{3,4}};
int[][] b = {{5,6},{7,8}};

int[][] c = new int[a.length][b.length];

if( a.length != b.length){
System.out.println();
}else{
for(int i=0;i<a.length;i++){
for(int j=0;i<b.length;j++){
c[i][j] = a[i][j] + b[i][j];
}

}
}
}
}

矩阵相减:

public class Test{

public static void main(String []args){

int[][] a= {{1,2},{3,4}};
int[][] b= {{5,6},{7,8}};

int[][] c = new int[a.length][b.length];

if( a.length != b.length){
System.out.println();
}else{
for(int i=0;i<a.length;i++){
for(int j=0;i<b.length;j++){
c[i][j] = a[i][j] - b[i][j];
}

}
}
}
}

矩阵相乘(简单直接):

public class Test{

public static void main(String []args){
int[][] a= {{1,2},{3,4}};
int[][] b= {{5,6},{7,8}};

int[][] c = new int[a.length][b.length];

if( a.length != b.length){
System.out.println("您输入的矩阵不正确!!!");
}else{
for(int i=0;i<a.length;i++){
for(int j=0;i<b.length;j++){
c[i][j] = 0;
for(int k=0;k<c.length;k++){
c[i][j] += a[i][k]*b[k][j]
}
}

}
}
}
}

矩阵相乘(利用分治思想):

public class Test {

public static void main(String[] args) {
// TODO Auto-generated method stub
int [][]a = {{1,2,3,4},{1,2,3,4},{1,2,3,4},{1,2,3,4}};
int [][]b = {{1,2,3,4},{1,2,3,4},{1,2,3,4},{1,2,3,4}};

int [][]c = flag(a,b,a.length);

for (int i = 0; i < c.length; i++) {
for (int j = 0; j < c.length; j++) {
System.out.print(c[i][j] + "\t");
}
System.out.println();
}
}

private static int[][] flag(int[][] a, int[][] b, int n) {

int[][] result = new int[n][n];

if (n == 1) {
result[0][0] = a[0][0]*b[0][0];
return result;
}

int [][]a11 = new int[n/2][n/2];
int [][]a12 = new int[n/2][n/2];
int [][]a21 = new int[n/2][n/2];
int [][]a22 = new int[n/2][n/2];
int [][]b11 = new int[n/2][n/2];
int [][]b12 = new int[n/2][n/2];
int [][]b21 = new int[n/2][n/2];
int [][]b22 = new int[n/2][n/2];

//将矩阵A分块
for (int i = 0; i < n/2; i++) {
for (int j = 0; j < n/2; j++) {
a11[i][j] = a[i][j];
}
}

for (int i = 0; i < n/2; i++) {
for (int j = 0; j < n/2; j++) {
a12[i][j] = a[i][j+n/2];
}
}

for (int i = 0; i < n/2; i++) {
for (int j = 0; j < n/2; j++) {
a21[i][j] = a[i+n/2][j];
}
}

for (int i = 0; i < n/2; i++) {
for (int j = 0; j < n/2; j++) {
a22[i][j] = a[i+n/2][j+n/2];
}
}

//将矩阵A分块
for (int i = 0; i < n/2; i++) {
for (int j = 0; j < n/2; j++) {
b11[i][j] = b[i][j];
}
}

for (int i = 0; i < n/2; i++) {
for (int j = 0; j < n/2; j++) {
b12[i][j] = b[i][j+n/2];
}
}

for (int i = 0; i < n/2; i++) {
for (int j = 0; j < n/2; j++) {
b21[i][j] = b[i+n/2][j];
}
}

for (int i = 0; i < n/2; i++) {
for (int j = 0; j < n/2; j++) {
b22[i][j] = b[i+n/2][j+n/2];
}
}

//求出各分块的相加与相减的值
int[][] s1 = del(b12,b22,n/2);
int[][] s2 = add(a11,a12,n/2);
int[][] s3 = add(a21,a22,n/2);
int[][] s4 = del(b21,b11,n/2);
int[][] s5 = add(a11,a22,n/2);
int[][] s6 = add(b11,b22,n/2);
int[][] s7 = del(a12,a22,n/2);
int[][] s8 = add(b21,b22,n/2);
int[][] s9 = del(a11,a21,n/2);
int[][] s10 = add(b11,b12,n/2);

//求出该运算中的7次乘法

int[][] M1 = flag(a11,s1,n/2);
int[][] M2 = flag(s2,b22,n/2);
int[][] M3 = flag(s3,b11,n/2);
int[][] M4 = flag(a22,s4,n/2);
int[][] M5 = flag(s5,s6,n/2);
int[][] M6 = flag(s7,s8,n/2);
int[][] M7 = flag(s9,s10,n/2);

//做最后的加减
int[][] C11 = add(del(add(M5,M4,n/2),M2,n/2),M6,n/2);
int[][] C12 = add(M1,M2,n/2);
int[][] C21 = add(M3,M4,n/2);
int[][] C22 = del(del(add(M5,M1,n/2),M3,n/2),M7,n/2);

for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++) {
if(i < n/2) {
if(j < n/2){
result[i][j] = C11[i][j];
}else{
result[i][j] = C12[i][j-n/2];
}
}else {
if(j < n/2){
result[i][j] = C21[i-n/2][j];
}else{
result[i][j] = C22[i-n/2][j-n/2];
}
}
}

return result;
}

private static int[][] add(int[][] a, int[][] b, int n) {
int[][] result = new int[n][n];
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
result[i][j] = a[i][j] + b[i][j];
}
}
return result;
}

private static int[][] del(int[][] a, int[][] b, int n) {
int[][] result = new int[n][n];
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
result[i][j] = a[i][j] - b[i][j];
}
}
return result;
}

}

时间: 2024-10-11 06:55:52

关于分治算法的个人理解的相关文章

再回首--分治算法

谈起分治算法,首先从字面意思理解:就是将一个问题划分成多个较小的问题的算法.其实正应题目的意思.其基本设计思想就是:将一个难以直接解决的大问题分解成一些规模较小的相同问题以便各个击破,分而治之. 设计步骤:1)分解:分解成若干子问题 2)求解:求解个子问题 3)合并:将子解合并成原问题的解. 在自考的时候,我们遇到的二路归并算法就属于一种分治法.当然,要学会算法,就要找到其核心,抓住其核心了,我们也就明白算法是怎么回事了.下面我们通过二路归并算法找到其核心. 例子:给出一列数:4,2,8,3.利

【数据结构】分治算法求解假硬币问题

问题描述: 概念 分治算法的基本思想是将一个大的复杂的问题分解成多个小的.容易解决的问题,通过解决这些小问题进而解决这个大问题. 使用分治算法需要待求解问题能够简化为若干个小规模的相同的问题,通过逐步划分,达到一个易于求解的阶段,而直接进行求解,在程序中可以使用递归方法来进行求解. 哈哈,说起来很抽象,举个例子就好理解了. 一个袋子里有n个硬币,其中一枚是假币,并且假币和真币一模一样,仅凭肉眼无法区分,仅知道假币比真币轻一些,请问如何查找到假币? 分治算法: 我们可以这样做: 将这n个硬币分成两

【算法】2 由股票收益问题再看分治算法和递归式

回顾分治算法 分治算法的英文名叫做"divide and conquer",它的意思是将一块领土分解为若干块小部分,然后一块块的占领征服,让它们彼此异化.这就是英国人的军事策略,但我们今天要看的是算法. 如前所述,分治算法有3步,在上一篇中已有介绍,它们对应的英文名分别是:divide.conquer.combine. 接下来我们通过多个小算法来深化对分治算法的理解. 二分查找算法 问题描述:在已排序的数组A中查找是否存在数字n. 1)分:取得数组A中的中间数,并将其与n比较 2)治:

【万字博文】分析与设计:插入排序和分治算法、递归和迭代的探讨

插入排序及其解决思路 算法的作用自然不用多说,无论是在校学生,还是已经工作多年,只要想在计算机这条道路走得更远,算法都是必不可少的. 就像编程语言中的"Hello World!"程序一般,学习算法一开始学的便是排序算法.排序问题在日常生活中也是很常见的,说得专业点: 输入是:n个数的一个序列<a1,a2,...,an?1,an> 输出是:这n个数的一个全新的序列<a,1,a,2,...,a,n?1,a,n>,其特征是a,1≤a,2≤...≤a,n?1≤a,n 举

算法系列之常用算法之一----分治算法

一.基本概念 在计算机科学中,分治法是一种很重要的算法.分治算法,字面上的解释是"分而治之",分治算法主要是三点: 1.将一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题----"分" 2.将最后子问题可以简单的直接求解----"治" 3.将所有子问题的解合并起来就是原问题打得解----"合" 这三点是分治算法的主要特点,只要是符合这三个特点的问题都可以使用分治算法进行解决(注意用词,是"

2.3.2 分析分治算法

当一个算法包含对其自身的递归调用时,我们往往可以用递归方程或递归式来描述其运行时间,该方程根据在较小输入上的运行时间来描述在规模为n的问题上的总运行时间.然后,我们可以使用数学工具来求解该递归式并给出算法性能的界. 分析算法运行时间的递归式来自基本模式的三个步骤.如前所述,我们假设T(n)是规模为n的一个问题的运行时间.若问题规模足够小,如对某个常量c,n<=c,则直接求解需要常量时间,我们将其写作O(1).假设把原问题分解成a个子问题,每个子问题是原问题的1/b.(对归并排序,a和b都为2,然

算法思想——分治算法

一.分治策略 “分而治之”,大问题能够拆成相似的小问题,记住这些小问题需要具有相似性.而后将小问题的每个解合成为大问题的解.所以说大问题如何拆,小问题如何合并才是这个算法最主要的一个思想.实际上很多算法如贪心算法,动态规划等等都是要求把大问题拆成小问题.而分治算法的重要一点就是要适用于能够重新把小问题的解合并为大问题的解. 二.分治法适用条件 1.该问题的规模缩小到一定程度就可以很容易解决: 2.该问题可以分解为若干个规模较小的相同问题,这里注意是最优子结构性质: 3.利用该问题分解出的子问题的

算法浅谈——分治算法与归并、快速排序(附代码和动图演示)

在之前的文章当中,我们通过海盗分金币问题详细讲解了递归方法. 我们可以认为在递归的过程当中,我们通过函数自己调用自己,将大问题转化成了小问题,因此简化了编码以及建模.今天这篇文章呢,就正式和大家聊一聊将大问题简化成小问题的分治算法的经典使用场景--排序. 排序算法 排序算法有很多,很多博文都有总结,号称有十大经典的排序算法.我们信手拈来就可以说上来很多,比如插入排序.选择排序.桶排序.希尔排序.快速排序.归并排序等等.老实讲这么多排序算法,但我们实际工作中并不会用到那么多,凡是高级语言都有自带的

分治算法(Divide and Conquer)

分治算法 在计算机科学中,分治法是建基于多项分支递归的一种很重要的算法范式.字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并. 分治法所能解决的问题一般具有以下几个特征: 问题的规模缩小到一定的程度就可以容易地解决 问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质 利用该问题分解出的子问题的解可以合并为该问题的解 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问