算法导论--分治法

来源:互联网 发布:tableview性能优化 编辑:程序博客网 时间:2024/06/05 15:05
分治法的思想:
分--将问题分解为规模更小的子问题;
治--将这些规模更小的子问题逐个击破;
合--将已解决的子问题合并,最终得出“母”问题的解;
例如:将一个数组A,从小到到大排序。
分治思想:我们可以将数组A分成2个数组,即A[0....A.length/2] 、A[A.length/2+1,A.length]。分别将它们进行从小到大的排序,然后在将2个数组          组合到一起,进行排序。有人要问了,为什么要这样呢?直接将他们直接进行排序不就行了吗?干嘛还要多此一举!
分析:如果直接将他们进行排序:例如,使用插入排序,那他的时间复杂度为O(n^2)。
如果使用分治思想进行排序,则它的时间复杂度为O(nlgn);所需时间将更少!那么nlgn这个时间复杂度是怎么计算出来的呢?其实这个倒是很简单        n>1,T(n)=2T(n/2)+0(n) ,如果每层时间复杂度是n,那他又几层呢?这是一个简单的等比数列,a1=1;Sn=n;q=2;算出来n=2^(x+1);当n足够大的时
候,n=2^x;所以,x=lgn. 所以总的时间复杂度为O(nlgn);
public class merge {        public static void main(String[] args) {          int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8,7};          print(data);          mergeSort(data);          System.out.println("排序后的数组:");          print(data);      }      public static void mergeSort(int[] data) {          sort(data, 0, data.length - 1);      }        public static void sort(int[] data, int left, int right) {          if (left >= right)              return;          // 找出中间索引          int center = (left + right) / 2;          // 对左边数组进行递归          sort(data, left, center);          // 对右边数组进行递归          sort(data, center + 1, right);          // 合并          merge(data, left, center, right);          print(data);      }        /**      * 将两个数组进行归并,归并前面2个数组已有序,归并后依然有序      *       * @param data      *            数组对象      * @param left      *            左数组的第一个元素的索引      * @param center      *            左数组的最后一个元素的索引,center+1是右数组第一个元素的索引      * @param right      *            右数组最后一个元素的索引      */      public static void merge(int[] data, int left, int center, int right) {          // 临时数组          int[] tmpArr = new int[data.length];          // 右数组第一个元素索引          int mid = center + 1;          // third 记录临时数组的索引          int third = left;          // 缓存左数组第一个元素的索引          int tmp = left;          while (left <= center && mid <= right) {              // 从两个数组中取出最小的放入临时数组              if (data[left] <= data[mid]) {                  tmpArr[third++] = data[left++];              } else {                  tmpArr[third++] = data[mid++];              }          }          // 剩余部分依次放入临时数组(实际上两个while只会执行其中一个)          while (mid <= right) {              tmpArr[third++] = data[mid++];          }          while (left <= center) {              tmpArr[third++] = data[left++];          }          // 将临时数组中的内容拷贝回原数组中          // (原left-right范围的内容被复制回原数组)          while (tmp <= right) {              data[tmp] = tmpArr[tmp++];          }      }        public static void print(int[] data) {          for (int i = 0; i < data.length; i++) {              System.out.print(data[i] + "\t");          }          System.out.println();      }    } 

0 0
原创粉丝点击