第二章 算法基础

  本章首先讲了插入排序算法, 然后分析了插入排序算法的时间复杂性,引出了分治法的设计思想,分析了分治算法。

  1. 插入排序  

  插入排序采用了增量算法:在排序子数组A[1...j-1]后,将单个元素A[j]插入到子数组的适当位置,产生排序好的子数组A[1....j]。

  

 1 package sort;
 2 
 3 import util.RandomArray;
 4 
 5 public class Insert {
 6     public static void insertSort(int[] array) {
 7         // 插入排序
 8         for (int i = 1; i < array.length; i++) {
 9             int key = array[i];
10             // Insert array[i] into the sorted sequence array[0....i-1]
11             int j = i - 1;
12             while (j >= 0 && array[j] > key) {
13                 array[j + 1] = array[j];
14                 j--;
15             }
16             array[j + 1] = key;
17         }
18     }
19 
20     public static void main(String arg[]) {
21         RandomArray randomArray = new RandomArray(10);
22 
23         // 排序前,先把内容打印出来
24         randomArray.display();
25 
26         insertSort(randomArray.value);
27 
28         // 排序后,先把内容打印出来
29         randomArray.display();
30 
31     }
32 }

  事先定义了一个随机数组的类,方便接下来的排序算法。

  

 1 package util;
 2 
 3 
 4 public class RandomArray {
 5     public int[] value;
 6     
 7     public RandomArray(int size) {
 8         value = new int[size];
 9         for (int i = 0; i < size; i++) {
10             value[i] = (int)(Math.random()*100) - 50;
11         }
12     }
13     
14     public void display() {
15         for (int i = 0; i < value.length; i++) {
16             System.out.print(value[i] + " ");
17         }
18         System.out.println();
19     }
20 }

  插入排序算法的最好情况是O(n),最坏的情况是O(n^2)。

  2. 归并排序

  许多有用的算法在结构上是递归的:为了解决一个给定的问题,算法一次或者多次的递归调用自身一解决紧密相关的若干子问题。这些算法典型地遵循分治法的思想:将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后再合并这些子问题的解来建立原问题的解。

  

 1 package sort;
 2 
 3 import util.RandomArray;
 4 
 5 public class Merge {
 6 
 7     public static void mergeSort(int[] array) {
 8         sort(array, 0, array.length - 1);
 9     }
10 
11     public static void sort(int[] array, int left, int right) {
12         if (left < right) {
13             int mid = (left + right) / 2;
14             sort(array, left, mid);
15             sort(array, mid + 1, right);
16             merge(array, left, mid, right);
17         }
18     }
19 
20     public static void merge(int[] array, int left, int mid, int right) {
21         int n1 = mid - left + 1;
22         int[] L = new int[n1 + 1];
23         
24         int n2 = right - mid;
25         int[] R = new int[n2 + 1];
26         
27         for (int i = 0; i < n1; i++) {
28             L[i] = array[left + i];
29         }
30         L[n1] = Integer.MAX_VALUE;
31         
32         for (int j = 0; j < n2; j++) {
33             R[j] = array[mid + j + 1];
34         }
35         R[n2] = Integer.MAX_VALUE;
36         
37         int i = 0;
38         int j = 0;
39         for (int k = left; k <= right; k++) {
40             if (L[i] <= R[j]) {
41                 array[k] = L[i];
42                 i++;
43             } else {
44                 array[k] = R[j];
45                 j++;
46             }
47         }
48     }
49 
50     public static void main(String[] args) {
51         // TODO Auto-generated method stub
52         RandomArray randomArray = new RandomArray(1000000);
53 
54         // 排序前,先把内容打印出来
55         // randomArray.display();
56 
57         mergeSort(randomArray.value);
58 
59         // 排序后,先把内容打印出来
60         // randomArray.display();
61         System.out.println("ends");
62     }
63 
64 }

   上面的merge方法使用了哨兵的方式,也可以不适用哨兵,代码如下:

  

 1 //不采用哨兵
 2     public static void merge(int[] array, int left, int mid, int right) {
 3         int n1 = mid - left + 1;
 4         int[] L = new int[n1];
 5         
 6         int n2 = right - mid;
 7         int[] R = new int[n2];
 8         
 9         for (int i = 0; i < n1; i++) {
10             L[i] = array[left + i];
11         }
12         
13         for (int j = 0; j < n2; j++) {
14             R[j] = array[mid + j + 1];
15         }
16         
17         int i = 0;
18         int j = 0;
19         for (int k = left; k <= right; k++) {
20             if(i == n1) {
21                 System.arraycopy(R, j, array, k, right-k+1);
22                 break;
23             }
24             
25             if(j == n2) {
26                 System.arraycopy(L, i, array, k, right-k+1);
27                 break;
28             }
29             
30             if (L[i] <= R[j]) {
31                 array[k] = L[i];
32                 i++;
33             } else {
34                 array[k] = R[j];
35                 j++;
36             }
37         }
38     }

  归并排序的算法效率为O(n*lgn),但在合并中分配了左右两个子数组,牺牲了一定的空间。

posted @ 2017-11-06 20:52  colmoon  阅读(92)  评论(0编辑  收藏  举报