关于分治算法的个人理解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于分治算法的个人理解相关的知识,希望对你有一定的参考价值。

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

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;
}

}

以上是关于关于分治算法的个人理解的主要内容,如果未能解决你的问题,请参考以下文章

关于点分治的理解

分治算法理解

无法理解 Closest-Pair 分治算法

算法--排序--分治与快速排序

分治策略 - 最大子序列问题

动态规划和分治法,贪心算法以及递归的再一次深刻理解和体会