package com.itwang.sort_search; /** * @ProjectName: JavaPractice * @Package: com.itwang.sort_search * @ClassName: BinarySearch * @Author: JikeWang * @Description: 二分查找 * @Date: 2018-08-28 21:21 * @Version: 1.0 */ public class Search { /** * @Method find * @Author JikeWang * @Version 1.0 * @Description 順序查找 * @param array 要查找的元素數組 * @param key 要查找的元素 * @Return int 返回查找結果 -1:表示沒有查找到 0~array.length-1: 表示查找到 * @Exception * @Date 2018-08-30 18:42 */ public int find(int[] array, int key){ int i; for (i = 0 ;i < array.length; i++){ if (array[i] == key){ break; } } if (i == array.length){ return -1;//若是沒有查找到 }else{ return i;//若是查找到 } } /** * @Method binarySearch * @Author JikeWang * @Version 1.0 * @Description 二分查找(折半查找)前提元素必須是有序的 * @param array 要查找的數組 * @param key 要查找的關鍵元素 * @Return int 返回的查找結果,若是找到則返回元素的位置,若是沒有找到則返回元素應該插入的位置 * @Exception * @Date 2018-08-28 21:28 */ public int binarySearch(int[] array, int key){ int low = 0, high = array.length - 1; while (low <= high){ int mid = (high + low) >> 1; if (array[mid] < key){ low = mid + 1; }else if (array[mid] > key){ high = mid - 1; }else { return mid; } } return low; } /********************************插入排序********************************/ /** * @Method insertSort * @Author JikeWang * @Version 1.0 * @Description 直接插入排序 * @param array 要排序的數組集合 * @Return void * @Exception * @Date 2018-08-30 18:44 */ void insertSort(int[] array){ //直接插入排序,假定前面是有序的,從1後面位置開始插入排序 System.out.println("---------直接插入排序---------"); for (int i = 1; i < array.length; i++){ int tmp = array[i]; int j = i - 1; //遍歷找到插入的位置 while ((j >= 0) && (tmp < array[j])){ array[j + 1] = array[j];//若是插入的元素小於當前元素,元素後移 j--; } //將要插入的元素插入到找到的位置(j+1)是因爲上面循環結束後減了一次1 array[j + 1] = tmp; } } /** * @Method binaryInsertSort * @Author JikeWang * @Version 1.0 * @Description 折半插入排序(跟直接插入排序同樣,只是在查找元素插入位置的時候利用了折半查找 * @param array 要排序的數組集合 * @Return void * @Exception * @Date 2018-08-30 18:45 */ void binaryInsertSort(int[] array){ System.out.println("---------折半插入排序---------"); for (int i = 1; i < array.length; i++){ int tmp = array[i]; int low = binarySearch(array,tmp); //元素後移 for (int j = i - 1; j >= low; j --){ array[j+1] = array[j]; } array[low] = tmp; } } /** * @Method shellSort * @Author JikeWang * @Version 1.0 * @Description 希爾排序(先將整個待排序記錄序列分割成若干子序列,分別進行直接插入排序, * 待整個序列中的記錄「基本有序」時,再對全體記錄進行一次直接插入排序) * 分割序列能夠根據某一增量進行分割 * @param array * @Return void * @Exception * @Date 2018-08-30 18:49 */ public void shellSort(int[] array){ //增量每次都是/2 for (int step = array.length / 2; step > 0; step /= 2){ //從增量那組開始進行插入排序,直至完畢 for (int i = step; i < array.length; i++){ int j = i; int tmp = array[j]; //j-step就是表明與它同組隔壁的元素 while (j - step >= 0 && tmp < array[j - step]){ array[j] = array[j - step]; j = j - step; } array[j] = tmp; } } } /********************************交換排序********************************/ /** * @Method bubbleSort * @Author JikeWang * @Version 1.0 * @Description 冒泡排序,每次循環經過比較相鄰的元素大小進行交換,最終會是最後一個元素時最大的。 * 第一輪,須要循環n-1次,最後一個元素最大, * 第二輪,須要循環n-2次,最後一個元素最大, * 以此類推,須要進行n輪,每輪循環n-i次 * @param array * @Return void * @Exception * @Date 2018-08-30 18:57 */ public void bubbleSort(int[] array){ System.out.println("---------冒泡排序---------"); //進行array.length次循環,每輪進行array.length - i次循環 for (int i = 1; i <= array.length; i++){ boolean flag = true; //設定一個標記,若爲true,則表示這次循環 //沒有進行交換,不然有交換 for (int j = 0; j < array.length - i; j++){ if (array[j] > array[j + 1]){ swap(array, j, j+1); flag = false; } } } } /** * @Method quickSort * @Author JikeWang * @Version 1.0 * @Description 快速排序(快速排序是對冒泡排序的一種改進,經過一趟排序將待排序列分割成獨立的兩部分, * 其中一部分記錄的關鍵字均比另外一部分記錄關鍵字小,而後分別對這兩部分記錄進行排序) * @param array * @param low * @param high * @Return void * @Exception * @Date 2018-08-30 19:01 */ public void quickSort(int[] array, int low, int high){ if (low >= high){ return; } int index = partition(array, low, high); quickSort(array, low, index - 1); quickSort(array, index + 1, high); } public int partition(int[] array, int low, int high) { //以第一個元素做爲樞軸值 int key = array[low]; while (low < high){ //從後半部分向前掃描 while (array[high] >= key && low < high) high--; //將後半部分小於樞軸值的元素放到前半部分 array[low] = array[high]; //從前半部分向後掃描 while (array[low] <= key && low < high) low++; //將前半部分大於樞軸值的元素放到後半部分 array[high] = array[low]; } array[low] = key; return low; } /********************************選擇排序********************************/ /** * @Method selectSort * @Author JikeWang * @Version 1.0 * @Description 簡單選擇排序(每一次首先選擇當前索引位置的元素是最小值,經過跟後面元素的比較,肯定最小元素位置, * 若是最小位置發生變化,則將最小位置的元素賦值到當前選擇的位置) * @param array * @Return void * @Exception * @Date 2018-08-30 19:01 */ public void selectSort(int[] array){ System.out.println("---------簡單選擇排序---------"); for (int i = 0; i < array.length - 1; i++){ int min = i; //每一趟循環比較,找到最小的元素的下標並賦值給min for (int j = i + 1;j < array.length; j++){ if (array[j] < array[min]) min = j; } //若是min發生變化,進行交換 if (min != i){ swap(array, min, i); } } } //構建大頂堆 public int[] buildMaxHeap(int[] array){ for (int i = array.length / 2 - 1;i >= 0;i--){ //從第一個非葉子節點從下至上,從右至左調整結構 adjustDownHeap(array, i, array.length); } return array; } //向下調整堆 private void adjustDownHeap(int[] array, int k, int length) { //取出當前元素 int tmp = array[k]; //i爲初始化爲節點k的左孩子,沿節點較大的子節點向下調整 for (int i = 2*k + 1; i < length - 1; i = 2*i + 1 ){ if (i < length && array[i] < array[i+1])//取節點較大的子節點的下標 i++;//若是節點的右孩子>左孩子,則取右孩子節點的下標 if (array[i] <= tmp) break;//根節點 >=左右子女中關鍵字較大者,調整結束 else{ //根節點 <左右子女中關鍵字較大者 array[k] = array[i];//將左右子結點中較大值array[i]調整到雙親節點上 k = i; //【關鍵】修改k值,以便繼續向下調整 } } array[k] = tmp;//被調整的結點的值放人最終位置 } /** * @Method heapSort * @Author JikeWang * @Version 1.0 * @Description 堆排序(堆排序首先須要構建堆,這裏是構建大頂堆,構建完畢後須要將元素從小到大整理出來, * 由於堆頂元素時最大值,經過從後向前操做,每次將堆頂元素賦值到當前位置,但每次賦值後, * 堆的結構就發生了變化,須要從新調整) * @param array * @Return void * @Exception * @Date 2018-08-30 19:01 */ public void heapSort(int[] array){ array = buildMaxHeap(array); //n-1趟的交換和建堆過程 for (int i = array.length - 1; i > 1;i--){ swap(array, 0, i);//將堆頂元素和堆低元素交換 adjustDownHeap(array, 0, i);//整理、將剩餘的元素整理成堆 } } /** * @Method deleteMax * @Author JikeWang * @Version 1.0 * @Description 刪除堆頂元素操做 * @param array * @Return int[] * @Exception * @Date 2018-08-30 19:02 */ public int[] deleteMax(int[] array){ //將堆的最後一個元素與堆頂元素交換,堆底元素值設爲-999996 array[0] = array[array.length-1]; array[array.length-1] = -99999; //對此時的根節點進行向下調整 adjustDownHeap(array, 0, array.length); return array; } /** * @Method insertData * @Author JikeWang * @Version 1.0 * @Description 插入操做:向大根堆array中插入數據data * @param array * @param data * @Return int[] * @Exception * @Date 2018-08-30 19:02 */ public int[] insertData(int[] array, int data){ array[array.length-1] = data; //將新節點放在堆的末端 int k = array.length-1; //須要調整的節點 int parent = (k-1)/2; //雙親節點 while(parent >=0 && data>array[parent]){ array[k] = array[parent]; //雙親節點下調 k = parent; if(parent != 0){ parent = (parent-1)/2; //繼續向上比較 }else{ //根節點已調整完畢,跳出循環 break; } } array[k] = data; //將插入的結點放到正確的位置 return array; } //兩個位置的元素交換值 private void swap(int[] array, int j, int i) { int tmp = array[j]; array[j] = array[i]; array[i] = tmp; } //打印元素 void print(int[] array){ for (int a : array) { System.out.print(a + "\t"); } System.out.println(); } public static void main(String[] args) { int[] array = {2,5,7,9,24}; int[] sort_array = {2,5,3,1}; Search search = new Search(); //二分查找(折半查找) int result = search.binarySearch(array, 10); System.out.println(result); //直接插入排序 //search.insertSort(sort_array); //折半插入排序 //search.binaryInsertSort(sort_array); //冒泡排序 //search.binaryInsertSort(sort_array); //簡單選擇排序 //search.selectSort(sort_array); //希爾排序 //search.shellSort(sort_array); //快速排序 //search.quickSort(sort_array, 0, sort_array.length - 1); search.heapSort(sort_array); search.print(sort_array); } }