分治算法及例题解析

什么是分治思想

字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。这个技巧是很多高效算法的基础,如二分法、快速排序、归并排序。

分治法适用的情况

分治法所能解决的问题一般具有以下几个特征:

  1. 该问题的规模缩小到一定的程度就可以容易地解决

  2. 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。

  3. 利用该问题分解出的子问题的解可以合并为该问题的解;

  4. 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。

分治法的基本步骤

分治法在每一层递归上都有三个步骤:

1 分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;

2 解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题

3 合并:将各个子问题的解合并为原问题的解。

快速排序

基本思想

将所有比枢轴元素小的放在其左边;

将所有比它大的放在其右边;

形成左右两个子表;

然后对左右两个子表再按照前面的算法进行排序,直到每个子表的元素只剩下一个。

快速排序用到了分而治之的思想。将一个数组分成两个数组的方法为

先从数组右边找到一个比枢轴元素小的元素,将数组的第一个位置赋值为该元素;
再从数组的左边找到一个比枢轴元素大的元素,将从上面取元素的位置赋值为该值;
依次进行,直到左右相遇,把枢轴元素赋值到相遇位置。

第一遍的过程如下

在这里插入图片描述

全部排序过程如下

在这里插入图片描述

Javascript实现快排

//普通法实现快速排序
function quick(arr,left,right){
var mid = arr[left];
while(left<right){
    while(left<right&&mid<=arr[right]){
        right--;
    }
    arr[left] = arr[right];
    while(left<right&&mid>=arr[left]){
        left++;
    }
    arr[right] = arr[left];
}
arr[right] = mid;
return left;
}
function quicksort(arr,left,right){
    var mid;
    if(left<right){
        mid = quick(arr,left,right);
        quicksort(arr,left,mid-1);
        quicksort(arr,mid+1,right);
    }
    return arr;
}
var arr = [39,28,55,87,66,3,17,39];
console.log(quicksort(arr,0,7));

在这里插入图片描述

//内置函数的做法
function quicksort(arr){
    if(arr.length<=1){
        return arr;
    }
    var left = [];
    var right = [];
    var value = arr.splice(0,1);
    var len = arr.length; 
    for(let i = 0;i<len;i++){
        if(arr[i]>value){
            right.push(arr[i]);
        }else{
            left.push(arr[i]);
        }
    }
    return quicksort(left).concat(value,quicksort(right));
}
var arr = [39,28,55,87,66,3,17,39];
console.log('排序前',arr)
console.log('排序后',quicksort(arr));

在这里插入图片描述

归并排序

基本思想

先将序列一次次分成子序列,直到子序列长度为1;再将已有序的子序列合并,得到完全有序的序列。运用了 分而治之的思想(分治法) 。

分治思想

首先把数组依次折半,分成小的子数组,直到每一个子数组的长度都为1;
然后合并子数组,在合并的过程中进行排序;

合并排序过程如下

在这里插入图片描述

全部排序过程如下

在这里插入图片描述

JavaScript代码实现

/*
 合并方法:
   @param arr 待排序数组
   @param left 左边序列的初始索引
   @param mid 中间索引(用来判断左边序列何时结束:到mid结束,右边序列何时开始:即mid+1)
   @param right 右边数组结束的索引
   @param temp 临时存储的数组
*/
function merge(arr,left,mid,rigth,temp){
    var i = left;
    var j = mid+1;
    var t = 0;
    while(i<=mid&&j<=rigth){
       if(arr[i]<=arr[j]){
            temp[t]=arr[i];
            t+=1;
            i+=1;
       }else{
           temp[t] = arr[j];
           t+=1;
           j+=1;
       }
    }
    while(i<=mid){
        temp[t]=arr[i];
        i+=1;
        t+=1;
    }
    while(j<=rigth){
        temp[t] = arr[j];
        t+=1;
        j+=1;
    }
    t=0;
    var k = left;
    while(k<=rigth){
        arr[k] = temp[t];
        t+=1;
        k+=1;
    }
}

function mergeSort(arr,left,rigth,temp){
    if(left<rigth){
        var mid = parseInt((left+rigth)/2);//中间索引
        mergeSort(arr,left,mid,temp);//左边递归分解
        mergeSort(arr,mid+1,rigth,temp);//右边递归分解
        merge(arr,left,mid,rigth,temp);//合并
    }
}

var arr = [2,5,3,10,-3,1,6,4];;
var temp = new Array(arr.length);
console.log('排序前',arr);
mergeSort(arr,0,arr.length-1,temp);
console.log('排序后',arr);


在这里插入图片描述

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力做一只合格的前端攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值