目錄html
1、查找與排序-1java
2、查找與排序-2git
4、查找與排序-4shell
6、遇到的問題和解決辦法bash
7、總結數據結構
8、參考資料測試
Searching.java
和Sorting.java
是書上已經寫好的類,只需進行junit測試就行。爲了體現查找的異常狀況,我在線性查找中添加了一個在數組中不存在的測試用例,二分查找則經過逆序(即降序)來體現異常狀況spa
首先把
Searching.java
和Sorting.java
放入cn.edu.besti.cs1623.zzr123包中,而後新建一個Test文件夾,把書上的兩個測試代碼放入其中,而後分別在IDEA和命令行下運行
參考《[Data Structure & Algorithm] 七大查找算法》
參考的博客中給出了七大查找方法,其中順序查找和二分查找以前已經實現並測試了,我須要實現剩下的五種查找方法並測試
插值查找相似於二分查找,只不過二分查找每次是取中點做爲查找點,從而排除一半的數據,插值查找是將查找點的選擇改進爲自適應選擇,即更加靠近查找對象。
public static int insertionSearch(int[] data, int target, int min, int max) { int mid = min+(target-data[min])/(data[max]-data[min])*(max-min); if(data[mid] == target) return data[mid]; else if(data[mid]>target) return insertionSearch(data, target, min, mid-1); else return insertionSearch(data, target, mid+1, max); }
也是二分查找的一種提高算法,經過運用黃金比例的概念在數列中選擇查找點進行查找,提升查找效率。一樣地,斐波那契查找也屬於一種有序查找算法。首先須要構造一個斐波那契數組
//構造一個斐波那契數組 private static void fibonacci(int F[]) { F[0]=0; F[1]=1; for(int i=2;i<MAX_SIZE;i++) F[i]=F[i-1]+F[i-2]; }
斐波那契查找與折半查找很類似,他是根據斐波那契序列的特色對有序表進行分割的。他要求開始表中記錄的個數爲某個斐波那契數小1,及n=F(k)-1;
開始將k值與第F(k-1)位置的記錄進行比較(及mid=low+F(k-1)-1),比較結果也分爲三種
1)相等,mid位置的元素即爲所求
2)>,low=mid+1,k-=2;
說明:low=mid+1說明待查找的元素在[mid+1,high]範圍內,k-=2 說明範圍[mid+1,high]內的元素個數爲n-(F(k-1))= Fk-1-F(k-1)=Fk-F(k-1)-1=F(k-2)-1個,因此能夠遞歸的應用斐波那契查找。
3)<,high=mid-1,k-=1。
說明:low=mid+1說明待查找的元素在[low,mid-1]範圍內,k-=1 說明範圍[low,mid-1]內的元素個數爲F(k-1)-1個,因此能夠遞歸 的應用斐波那契查找。
/*定義斐波那契查找法*/ //data爲要查找的數組,length爲數組長度,target爲要找的目標 public static int fibonacciSearch(int data[],int length,int target) { int min = 0; int max = length-1; int F[] = new int[MAX_SIZE]; fibonacci(F); int k=0; while(length>F[k]-1)//計算length位於斐波那契數列的位置 k++; int []temp;//將數組data擴展到F[k]-1的長度 temp= Arrays.copyOf(data,F[k]-1); for(int i=length;i<F[k]-1;i++) temp[i]=data[length-1]; while(min<=max) { int mid=min+F[k-1]-1; if(target<temp[mid]) { max=mid-1; k-=1; } else if(target>temp[mid]) { min=mid+1; k-=2; } else { if(mid<length) return data[mid]; //若相等則說明mid即爲查找到的位置 else return data[length-1]; //若mid>=n則說明是擴展的數值,返回n-1 } } return -1;//未查找到 }
我這裏的數表查找是用的以前實現的二叉查找樹實現的,先構造一顆二叉查找樹,而後將要查找的數組中的元素依次添加到二叉查找樹中,再調用其中的find方法便可
//數表查找,利用二叉查找樹實現 public static Comparable treeSearch(int []data,int target) { LinkedBinarySearchTree<Integer> bsTree = new LinkedBinarySearchTree<>(); for(int i=0;i<data.length;i++){ bsTree.add(data[i]); } return bsTree.find(target); }
分塊查找又稱索引順序查找,它是順序查找的一種改進方法。
詳情參考《數據結構Java版的查找算法實現》
(1)算法思想:
將n個數據元素"按塊有序"劃分爲m塊(m ≤ n)。每一塊中的結點沒必要有序,但塊與塊之間必須"按塊有序";即第1塊中任一元素的關鍵字都必須小於第2塊中任一元素的關鍵字;而第2塊中任一元素又都必須小於第3塊中的任一元素,……
(2)算法流程:
- step1 先選取各塊中的最大關鍵字構成一個索引表;
- step2 查找分兩個部分:先對索引表進行二分查找或順序查找,以肯定待查記錄在哪一塊中;而後,在已肯定的塊中用順序法進行查找。
/** * 分塊查找 * 採用數組保存區塊的極值和起始下標 * @param data 查找數組 * @param n 分塊個數 */ public static int blockSearch(int []data,int target,int n) { HashMap<Integer, Integer> block = new HashMap<>(); int tem = data[0]; for (int i = 0; i < data.length - 1; i++) { if (i % n == 0) { //起始分塊 if ((i + n) >= data.length - 1) { //判斷是不是最後一個區塊 最後一個區塊元素可能小於或大於前面區塊元素 for (int j = i; j < data.length; j++) { //區塊內查找極值 if (data[j] > tem) { tem = data[j]; } } //保存區塊極值和起始下標 block.put(tem, i); } else { for (int j = i; j < i + n; j++) { //區塊內查找極值 if (data[j] > tem) { tem = data[j]; } } //保存區塊極值和起始下標 block.put(tem, i); //初始化區塊比較值 tem = data[i + n - 1]; } } } //獲取索引極值進行排序 Iterator<Integer> ite = block.keySet().iterator(); int[] index1 = new int[block.size()]; int i = 0; while (ite.hasNext()){ index1[i++] = ite.next(); } //索引極值從小到大排序 Arrays.sort(index1); //查找元素所在區塊 for (int j = 0; j < index1.length; j++) { if (target <= index1[j]){ //小於索引值說明在此區塊內進行查找 int start = block.get(index1[j]); int end = 0; if (j != index1.length -1){ end = block.get(index1[j+1]); }else { end = data.length; } //查找區塊元素位置 for (int k = start; k < end; k++) { if (target == data[k]){ return data[k]; } } } } return -1;//找不到返回-1 }
構造一個HashMap,把查找數組中的元素做爲value,它的hash值做爲key,每次查找經過計算目標的hash值直接找到目標
//哈希查找 public static int hashSearch(int data[],int target) { HashMap<Integer,Integer> hashMap = new HashMap<>(); for(int i=0;i<data.length;i++) hashMap.put(Integer.hashCode(data[i]),data[i]); int key = Integer.hashCode(target); if(hashMap.containsKey(key)) return hashMap.get(key); return -1;//找不到返回-1 }
6.測試截圖
依次實現四種排序方法
希爾排序是插入排序的一種,其基本原理是,現將待排序的數組元素分紅多個子序列,使得每一個子序列的元素個數相對較少,而後對各個子序列分別進行直接插入排序,待整個待排序列「基本有序」後,最後在對全部元素進行一次直接插入排序。詳情可參考《【排序算法】希爾排序原理及Java實現》
//希爾排序 public static void shellSort(Comparable []data) { Comparable temp; int dataLength = data.length / 2; int pointer; while (dataLength != 0) { for (int i = dataLength; i < data.length; i++) { temp = data[i]; pointer = i - dataLength; while (pointer >= 0 && temp.compareTo(data[pointer])<0) { data[pointer + dataLength] = data[pointer]; pointer -= dataLength; if (pointer > data.length) { break; } data[pointer + dataLength] = temp; } } dataLength /= 2; } }
堆排序的實現可利用教材上的最大堆,先構造一個最大堆,而後將要排序的數組依次放入堆中,再依次取出,只不過獲得的是降序排列,只需將第一個取出的元素放在數組最後位置接下來依次類推,便可獲得升序排列
//堆排序 public static void heapSort(int []data) { LinkedMaxHeap<Integer> heap = new LinkedMaxHeap<>(); int length = data.length; for(int i=0;i<length;i++) heap.add(data[i]); for(int j=0;j<length;j++) data[length-1-j] = heap.removeMax(); }
桶排序是一種以空間換時間的排序方法,桶排序的基本思想是:把數組 arr 劃分爲n個大小相同子區間(桶),每一個子區間各自排序,最後合併。
計數排序是桶排序的一種特殊狀況,能夠把計數排序當成每一個桶裏只有一個元素的狀況。詳情參考《計數排序和桶排序(Java實現)》
(1)找出待排序數組中的最大值max、最小值min
(2)咱們使用 動態數組ArrayList 做爲桶,桶裏放的元素也用 ArrayList 存儲。桶的數量爲(max-min)/arr.length+1
(3)遍歷數組 arr,計算每一個元素 arr[i] 放的桶
(4)每一個桶各自排序
(5)遍歷桶數組,把排序好的元素放進輸出數組
//桶排序 public static void bucketSort(int []arr) { int max = Integer.MIN_VALUE; int min = Integer.MAX_VALUE; for (int i = 0; i < arr.length; i++) { max = Math.max(max, arr[i]); min = Math.min(min, arr[i]); } //桶數 int bucketNum = (max - min) / arr.length + 1; ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum); for (int i = 0; i < bucketNum; i++) { bucketArr.add(new ArrayList<Integer>()); } //將每一個元素放入桶 for (int i = 0; i < arr.length; i++) { int num = (arr[i] - min) / (arr.length); bucketArr.get(num).add(arr[i]); } //對每一個桶進行排序 for (int i = 0; i < bucketArr.size(); i++) { Collections.sort(bucketArr.get(i)); } int index = 0; for (int i = 0; i < bucketNum; i++) { for (int j = 0; j < bucketArr.get(i).size(); j++) { arr[index] = bucketArr.get(i).get(j); index++; } } }
利用二叉查找樹進行排序,二叉查找樹的中序遍歷就是樹中元素的升序排列,因此我先構造一顆二叉查找樹,而後把元素添加進去,獲得中序遍歷,在依次放入數組中便可
//二叉樹排序 public static void binaryTreeSort(int []data) { LinkedBinarySearchTree<Integer> bsTree = new LinkedBinarySearchTree<>(); int length = data.length; for(int i=0;i<length;i++) bsTree.add(data[i]); ArrayList<Integer> list = (ArrayList<Integer>) bsTree.inorder(); for(int j=0;j<length;j++) data[j] = list.remove(0); }
5.測試截圖
課上沒完成,課後補博客,詳見博客《20162311 編寫Android程序測試查找排序算法》
本次的實驗主要目的是增強對排序和查找算法的理解,以前已經學過一些算法,也作過相關測試,但都是書上實現好的,此次是要本身補充實現一些書上沒有的查找和排序的算法。經過本身去實現,咱們能更好的理解和掌握這些算法,而不是僅僅停留在使用的層面上