之前写了好多关于排序算法的文章,基本上都是总结性质的,其实排序算法的研究很细致,但是我的博客都基本上只是给出了大体的思路和Java程序实现,算法写起来比较繁琐,感兴趣的话,自己去研究下吧,我推荐算法导论这本书。
看到这么多的排序算法,如果要将其真正用到Java程序里边的话,未免也太复杂了,因为要为每一种算法在使用之前都要先创建一个实例,然后才能使用,这样就暴露了实现,不符合面向对象的基本要求,因此建立一个工厂类,然后让工厂来负责具体的算法的创建,客户端程序员就不必知道具体的算法了,而且,这样做就可以统一接口。
简单工厂的本质是:封装实现。
需要注意的是简单工厂的重点在于选择,实现是已经做好了的。简单工厂的目的为在于客户端来选择相应的实现,从而使得客户端和实现之间的解耦。这样一来,具体的实现,就不用变动客户端的代码了,这个变化会被简单工厂吸收和屏蔽。
使用我之前写过的算法的例子,可以这样来应用简单工厂模式。
首先,建立一个具体算法的接口,实现面向接口的编程。接口定义如下:
1 package com.alfred.sort; 2 3 public interface SortAlgorithm { 4 /** 5 * 将数组按照升序排序 6 * 7 * @param A 8 * int数组,按升序排列 9 */ 10 public void sort(int[] A); 11 12 /** 13 * 将数组按照升序或降序排序 14 * 15 * @param A 16 * int数组 17 * @param isInc 18 * 是否升序,true为升序,false为降序 19 */ 20 public void sort(int[] A, boolean isInc); 21 }
然后,建立每一个算法的具体实现,每一个算法都要实现这个接口。
1 package com.alfred.sort; 2 3 public class InsertionSort implements SortAlgorithm { 4 5 @Override 6 public void sort(int[] A) { 7 InsertSort(A, true); 8 } 9 10 @Override 11 public void sort(int[] A, boolean isInc) { 12 InsertSort(A, isInc); 13 } 14 15 /** 16 * 插入排序算法 17 * 18 * @param A 19 * int数组 20 * @param isInc 21 * 是否升序,true为升序,false为降序 22 */ 23 private void InsertSort(int[] A, boolean isInc) { 24 int len = A.length; 25 int key = 0; 26 int i = 0; 27 for (int j = 1; j < len; j++) { 28 key = A[j]; 29 i = j - 1; 30 while (i >= 0 && (isInc ? A[i] > key : A[i] < key)) { 31 A[i + 1] = A[i]; 32 i = i - 1; 33 } 34 A[i + 1] = key; 35 } 36 } 37 }
1 package com.alfred.sort; 2 3 public class MergeSort implements SortAlgorithm { 4 5 @Override 6 public void sort(int[] A) { 7 mergeSort(A, 0, A.length - 1, true); 8 } 9 10 @Override 11 public void sort(int[] A, boolean isInc) { 12 mergeSort(A, 0, A.length - 1, isInc); 13 } 14 15 /** 16 * 合并排序 17 * @param A 18 * int数组 19 * @param p 20 * 起始位置 21 * @param r 22 * 终止位置 23 * @param isInc 24 * 是否升序,true为升序,false为降序 25 */ 26 private void mergeSort(int[] A, int p, int r, boolean isInc) { 27 int q = 0; 28 if (p < r) { 29 q = (p + r) / 2; 30 mergeSort(A, p, q, isInc); 31 mergeSort(A, q + 1, r, isInc); 32 merge(A, p, q, r, isInc); 33 } 34 } 35 36 /** 37 * 合并两个排好的序列 38 * @param A 39 * int数组 40 * @param p 41 * 起始位置 42 * @param q 43 * 中间位置 44 * @param r 45 * 终止位置 46 * @param isInc 47 * isInc 是否升序,true为升序,false为降序 48 */ 49 private void merge(int[] A, int p, int q, int r, boolean isInc) { 50 int nLeft = q - p + 1; 51 int nRight = r - q; 52 int[] left = new int[nLeft]; 53 int[] right = new int[nRight]; 54 int i = 0, j = 0, k = 0; 55 for (i = 0; i < nLeft; i++) { 56 left[i] = A[p + i]; 57 } 58 for (j = 0; j < nRight; j++) { 59 right[j] = A[q + j + 1]; 60 } 61 i = 0; 62 j = 0; 63 for (k = p; k <= r; k++) { 64 if (isInc ^ (left[i] <= right[j])) { 65 A[k] = right[j]; 66 j++; 67 } else { 68 A[k] = left[i]; 69 i++; 70 } 71 72 if (i == nLeft) { 73 k++; 74 for (; j < nRight; j++) { 75 A[k] = right[j]; 76 k++; 77 } 78 } 79 if (j == nRight) { 80 k++; 81 for (; i < nLeft; i++) { 82 A[k] = left[i]; 83 k++; 84 } 85 } 86 } 87 } 88 }
1 package com.alfred.sort; 2 3 public class HeapSort implements SortAlgorithm { 4 5 private IntArray A = null; 6 7 public HeapSort() { 8 A = new IntArray(); 9 } 10 11 private class IntArray { 12 public int[] aArray = null; 13 public int heapSize = 0; 14 } 15 16 @Override 17 public void sort(int[] A) { 18 maxHeapSort(A); 19 } 20 21 @Override 22 public void sort(int[] A, boolean isInc) { 23 if (isInc) { 24 maxHeapSort(A); 25 } else { 26 minHeapSort(A); 27 } 28 } 29 30 /** 31 * 最大堆排序,升序 32 * 33 * @param A 34 * int数组 35 */ 36 private void maxHeapSort(int[] A) { 37 this.A.aArray = A; 38 this.A.heapSize = A.length; 39 buildMaxHeap(this.A); 40 for (int i = A.length; i >= 2; i--) { 41 exchange(1, i); 42 this.A.heapSize = this.A.heapSize - 1; 43 maxHeapify(this.A, 1); 44 } 45 } 46 47 /** 48 * 最小堆排序,降序 49 * 50 * @param A 51 * int数组 52 */ 53 private void minHeapSort(int[] A) { 54 this.A.aArray = A; 55 this.A.heapSize = A.length; 56 buildMinHeap(this.A); 57 for (int i = A.length; i >= 2; i--) { 58 exchange(1, i); 59 this.A.heapSize = this.A.heapSize - 1; 60 minHeapify(this.A, 1); 61 } 62 } 63 64 /** 65 * 使得以index为根的子树成为最大堆 66 * 67 * @param A 68 * int数组 69 * @param index 70 * 以index为根,从1开始 71 */ 72 private void maxHeapify(IntArray A, int index) { 73 while (index < A.heapSize / 2 + 1) { 74 int left = left(index); 75 int right = right(index); 76 int largest = 0; 77 if (left <= A.heapSize && A.aArray[left - 1] > A.aArray[index - 1]) { 78 largest = left; 79 } else { 80 largest = index; 81 } 82 if (right <= A.heapSize 83 && A.aArray[right - 1] > A.aArray[largest - 1]) { 84 largest = right; 85 } 86 if (index != largest) { 87 exchange(index, largest); 88 index = largest; 89 } else { 90 index = A.heapSize / 2 + 1; 91 } 92 } 93 } 94 95 /** 96 * 使得以index为根的子树成为最小堆 97 * 98 * @param A 99 * int数组 100 * @param index 101 * 以index为根,从1开始 102 */ 103 private void minHeapify(IntArray A, int index) { 104 while (index < A.heapSize / 2 + 1) { 105 int left = left(index); 106 int right = right(index); 107 int smallest = 0; 108 if (left <= A.heapSize && A.aArray[left - 1] < A.aArray[index - 1]) { 109 smallest = left; 110 } else { 111 smallest = index; 112 } 113 if (right <= A.heapSize 114 && A.aArray[right - 1] < A.aArray[smallest - 1]) { 115 smallest = right; 116 } 117 if (index != smallest) { 118 exchange(index, smallest); 119 index = smallest; 120 } else { 121 index = A.heapSize / 2 + 1; 122 } 123 } 124 } 125 126 /** 127 * 建最大堆 128 * 129 * @param A 130 * int数组 131 */ 132 private void buildMaxHeap(IntArray A) { 133 for (int i = A.aArray.length / 2; i >= 1; i--) { 134 maxHeapify(A, i); 135 } 136 } 137 138 /** 139 * 建最小堆 140 * 141 * @param A 142 * int数组 143 */ 144 private void buildMinHeap(IntArray A) { 145 for (int i = A.aArray.length / 2; i >= 1; i--) { 146 minHeapify(A, i); 147 } 148 } 149 150 private int left(int index) { 151 return 2 * index; 152 } 153 154 private int right(int index) { 155 return 2 * index + 1; 156 } 157 158 private void exchange(int i, int j) { 159 int temp = A.aArray[i - 1]; 160 A.aArray[i - 1] = A.aArray[j - 1]; 161 A.aArray[j - 1] = temp; 162 } 163 164 }
1 package com.alfred.sort; 2 3 import java.util.Random; 4 5 public class QuickSort implements SortAlgorithm { 6 7 private Random rand = null; 8 9 public QuickSort() { 10 rand = new Random(); 11 } 12 13 @Override 14 public void sort(int[] A) { 15 randomizedQuickSort(A, 1, A.length, true); 16 } 17 18 @Override 19 public void sort(int[] A, boolean isInc) { 20 randomizedQuickSort(A, 1, A.length, isInc); 21 } 22 23 /** 24 * 随机化的快速排序 25 * @param A 要排序的int数组 26 * @param p 起始位置 27 * @param r 终止位置 28 * @param isInc 是否升序,true为升序,false为降序 29 */ 30 private void randomizedQuickSort(int[] A, int p, int r, boolean isInc) { 31 if (p < r) { 32 int q = randomizedPartition(A, p, r, isInc); 33 randomizedQuickSort(A, p, q - 1, isInc); 34 randomizedQuickSort(A, q + 1, r, isInc); 35 } 36 } 37 38 /** 39 * 随机化的对数组的划分 40 * @param A 要划分的int数组 41 * @param p 起始位置 42 * @param r 终止位置 43 * @param isInc 是否升序,true为升序,false为降序 44 * @return 划分数组的下标 45 */ 46 private int randomizedPartition(int[] A, int p, int r, boolean isInc) { 47 int i = rand.nextInt(r - p); 48 exchange(A, r, i + p); 49 return partition(A, p, r, isInc); 50 } 51 52 /** 53 * 对数组进行划分 54 * @param A 要划分的int数组 55 * @param p 起始位置 56 * @param r 终止位置 57 * @param isInc 是否升序,true为升序,false为降序 58 * @return 划分数组的下标 59 */ 60 private int partition(int[] A, int p, int r, boolean isInc) { 61 int x = A[r - 1]; 62 int i = p - 1; 63 for (int j = p; j <= r - 1; j++) { 64 if (isInc ? A[j - 1] <= x : A[j - 1] >= x) { 65 i++; 66 exchange(A, i, j); 67 } 68 } 69 exchange(A, i + 1, r); 70 return i + 1; 71 } 72 73 private void exchange(int[] A, int i, int j) { 74 int temp = A[i - 1]; 75 A[i - 1] = A[j - 1]; 76 A[j - 1] = temp; 77 } 78 }
接下来,建立一个工厂类来为客户端选择具体的算法实现。
1 package com.alfred.sort; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.util.Properties; 6 7 public class SortFactory { 8 9 public static SortAlgorithm getSortAlgorithm(String type) { 10 11 Properties prop = new Properties(); 12 InputStream in = null; 13 14 try{ 15 in = SortFactory.class.getResourceAsStream("FactoryConfig.properties"); 16 prop.load(in); 17 }catch(IOException e){ 18 System.out.println("装载配置文件出错,具体的堆栈信息如下:"); 19 e.printStackTrace(); 20 }finally{ 21 try{ 22 in.close(); 23 }catch(IOException e){ 24 e.printStackTrace(); 25 } 26 } 27 28 SortAlgorithm sortAlgorithm = null; 29 try{ 30 sortAlgorithm = (SortAlgorithm)Class.forName(prop.getProperty(type)).newInstance(); 31 }catch(InstantiationException e){ 32 e.printStackTrace(); 33 }catch(IllegalAccessException e){ 34 e.printStackTrace(); 35 }catch(ClassNotFoundException e){ 36 e.printStackTrace(); 37 } 38 return sortAlgorithm; 39 } 40 41 private SortFactory() { 42 43 } 44 }
其中反射用的配置文件如下:
1 insert_sort = com.alfred.sort.InsertionSort 2 merge_sort = com.alfred.sort.MergeSort 3 heap_sort = com.alfred.sort.HeapSort 4 quick_sort = com.alfred.sort.QuickSort
当然,还有之前简化的打印类:
1 package com.alfred.sort; 2 3 public class Print { 4 public static void print() { 5 System.out.println(); 6 } 7 8 public static void print(boolean x) { 9 System.out.println(x); 10 } 11 12 public static void print(char x) { 13 System.out.println(x); 14 } 15 16 public static void print(char[] x) { 17 System.out.println(x); 18 } 19 20 public static void print(double x) { 21 System.out.println(x); 22 } 23 24 public static void print(float x) { 25 System.out.println(x); 26 } 27 28 public static void print(int x) { 29 System.out.println(x); 30 } 31 32 public static void print(long x) { 33 System.out.println(x); 34 } 35 36 public static void print(Object x) { 37 System.out.println(x); 38 } 39 40 public static void print(String x) { 41 System.out.println(x); 42 } 43 44 private Print() { 45 46 } 47 }
还有定义算法名称的常量类:
1 package com.alfred.sort; 2 3 public class AlgorithmConstants { 4 5 public static final String INSERT_SORT = "insert_sort"; 6 public static final String MERGE_SORT = "merge_sort"; 7 public static final String HEAP_SORT = "heap_sort"; 8 public static final String QUICK_SORT = "quick_sort"; 9 10 private AlgorithmConstants() { 11 12 } 13 }
最后,来写一个测试类来测试一下吧!
1 package com.alfred.sort; 2 3 import static com.alfred.sort.Print.print; 4 5 public class SortMain { 6 7 public static void main(String[] args) { 8 9 int[] A = new int[] { 23, 45, 36, 78, 45, 16, 59, 62, 569 }; 10 int[] aCopy = null; 11 print("原始数组:"); 12 printIntArray(A); 13 14 /********************** 15 * 插入排序 16 *********************/ 17 SortAlgorithm insertSort = SortFactory 18 .getSortAlgorithm(AlgorithmConstants.INSERT_SORT); 19 print("插入排序,升序排列:"); 20 aCopy = A.clone(); 21 insertSort.sort(aCopy); 22 printIntArray(aCopy); 23 print("插入排序,降序排列:"); 24 aCopy = A.clone(); 25 insertSort.sort(aCopy, false); 26 printIntArray(aCopy); 27 28 /********************** 29 * 合并排序 30 *********************/ 31 SortAlgorithm mergeSort = SortFactory 32 .getSortAlgorithm(AlgorithmConstants.MERGE_SORT); 33 print("合并排序,升序排列:"); 34 aCopy = A.clone(); 35 mergeSort.sort(aCopy); 36 printIntArray(aCopy); 37 print("合并排序,降序排列:"); 38 aCopy = A.clone(); 39 mergeSort.sort(aCopy, false); 40 printIntArray(aCopy); 41 42 /********************** 43 * 堆排序 44 *********************/ 45 SortAlgorithm heapSort = SortFactory 46 .getSortAlgorithm(AlgorithmConstants.HEAP_SORT); 47 print("最大堆排序,升序排列:"); 48 aCopy = A.clone(); 49 heapSort.sort(aCopy); 50 printIntArray(aCopy); 51 print("最小堆排序,降序排列:"); 52 aCopy = A.clone(); 53 heapSort.sort(aCopy, false); 54 printIntArray(aCopy); 55 56 /********************** 57 * 快速排序 58 *********************/ 59 SortAlgorithm quickSort = SortFactory 60 .getSortAlgorithm(AlgorithmConstants.QUICK_SORT); 61 print("快速排序,升序排列:"); 62 aCopy = A.clone(); 63 quickSort.sort(aCopy); 64 printIntArray(aCopy); 65 print("快速排序,降序排列:"); 66 aCopy = A.clone(); 67 quickSort.sort(aCopy, false); 68 printIntArray(aCopy); 69 70 } 71 72 private static void printIntArray(int[] A){ 73 int row = A.length / 10 + 1; 74 int index = 0; 75 for(int i = 0; i < row; i++){ 76 for(int j = 0; j < 10; j++){ 77 index = i * 10 + j; 78 if(index >= A.length){ 79 break; 80 }else{ 81 boolean x = (index + 1) % 10 == 0 || index == A.length - 1; 82 if(x){ 83 System.out.print(A[index]); 84 }else{ 85 System.out.print(A[index] + ","); 86 } 87 } 88 } 89 } 90 print(); 91 } 92 }
输出为:
原始数组:
23,45,36,78,45,16,59,62,569
插入排序,升序排列:
16,23,36,45,45,59,62,78,569
插入排序,降序排列:
569,78,62,59,45,45,36,23,16
合并排序,升序排列:
16,23,36,45,45,59,62,78,569
合并排序,降序排列:
569,78,62,59,45,45,36,23,16
最大堆排序,升序排列:
16,23,36,45,45,59,62,78,569
最小堆排序,降序排列:
569,78,62,59,45,45,36,23,16
快速排序,升序排列:
16,23,36,45,45,59,62,78,569
快速排序,降序排列:
569,78,62,59,45,45,36,23,16
从这个结果可以看出,所有的算法都能完成排序的工作,而且用了简单工厂模式之后,客户端程序就再也不需要知道具体的排序算法的实现了。