其實小編是不太想寫關於java的相關文章,由於是這個編程語言實在是會用的人太多了,網上的博文數不勝數,不必在重複造輪子了,可是雖然java這門語言會用的人不少,可是會用、掌握、熟練、和精通可不是鬧着玩的,想要達到精通的級別,小編敢說,一個正規的開發公司能過達到精通java的開發人員屈指可數,因此小編這裏就跳過關於java哪些簡單的API 、語法,直接給你們介紹一些相對提高能力,而且不是那麼基礎的知識,說不定之後面試就會用到,尤爲是排序,真的,不曉得爲啥都喜歡在面試的時候出排序的題,實際大數據開發中真正手寫排序的還真很少,我想多是各個面試官想要看到的是,各個應聘者是否可以get到排序算法的精髓吧。
好了,每次寫博客都要廢話一堆,自我反省,可是不想改變,接下來小編介紹幾種建立的排序算法以及他們的java實現。java
原理:從第一個元素開始,和它相鄰的比較,若是前面一個元素大於後面一個元素,就把他們互換位置。
原理圖:
代碼實現:面試
public static void main(String[] args) { int arr[] = { 15, 16, 145, 91, 9, 5, 0 }; int temp1=0; for(int i=0;i<arr.length-1;i++){ //控制循環次數:arr.length-1 for(int j=0;j<arr.length-i-1;j++){ //控制比較次數:arr.length-i-1 if(arr[j]>arr[j+1]){ temp1=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp1; } } } }
加強版冒泡排序:算法
public static void main(String[] args) { int arr[] = { 1,0,2,3,4,5,6,7,8 }; int temp1; for(int i=0;i<arr.length-1;i++){ //控制循環次數:arr.length-1 boolean flag=true; //判斷內層循環是否執行 for(int j=0;j<arr.length-i-1;j++){ //控制比較次數:arr.length-i-1 if(arr[j]>arr[j+1]){ temp1=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp1; flag=false; } } if(flag){ //若是內層循環的if一次都沒有執行,說明已經排序結束 break; } }
原理:從第一個位置開始,將他與後面的全部元素比較,若是前面大於後面的,就交換位置。
原理圖:
代碼實現:編程
public static void main(String[] args) { int arr[] = { 45,15,48,9,3,65,22 }; for(int i=0;i<arr.length-1;i++){ //控制位置,從第一個位置開始,到倒數第二個位置 for(int j=i+1;j<arr.length;j++){ //當前位置的下一個位置開始,與後面的全部比較 if(arr[i]>arr[j]){ int temp=arr[i]; arr[i]=arr[j]; arr[j]=temp; } } }
原理:從第二個元素位置開始,將他與他以前的元素比較,若是比以前的元素小,就將他插入到,那個元素的前面。
原理圖:
代碼實現:數組
public static void main(String[] args) { int arr[] = { 45, 15, 48, 9, 3, 65, 22 }; // 插入排序 int temp1; for (int i = 1; i < arr.length; i++) { //從第二個數開始,一直到最後一個數 for (int j = 0; j < i; j++) { //i以前的全部數,所有比較 if (arr[i] < arr[j]) { temp1 = arr[i]; for (int k = i; k > j; k--) { //將前面的數據把後面的覆蓋,從j開始,一直到i arr[k] = arr[k - 1]; } arr[j] = temp1; } } }
原理:先選取一個基準點,做用:基準點左側小於基準點的數據 基準點右側放的數據都是大於基準點的數據。基準點:最經常使用的基準點選第一個,最終一個大數組不停的進行查分 拆分的最終結果每一個數組只有一個元素。
原理圖:
解釋:大循環中有兩個循環,一個是從右往左,找比基準點小的,一個是從左往右找比基準點大的(找到以後,與基準點交換位置)。最終大循環,在left>=right時結束。
(2) 快排拆分:
解釋:使用遞歸的方式,將數組左右兩邊一次次拆分,直到left>=right時,遞歸結束。
代碼實現:編程語言
public class QuickSort { public static void main(String[] args) { int arr[]= {2,7,1,2,8,1,3,9,415,189,123}; sort(arr,0,arr.length-1); System.out.println(Arrays.toString(arr)); } public static void sort(int [] arr,int left ,int right) { //遞歸的出口,當左側==右側 if(left>=right) { return; } //獲取基準點 int point=getPoint(arr,left,right); //左邊排序(遞歸) sort(arr,left,point-1); //右邊排序(遞歸) sort(arr,point+1,right); } public static int getPoint(int [] arr,int left ,int right) { int key=arr[left]; while(left<right) { //從右向左循環,只要右邊的比基準點大,就繼續循序 while(key<=arr[right]&&left<right) { //每循環一次,right的索引向左移一個 right--; } //交換基準點的位置 arr[left]=arr[right]; //從左向右循環,只要左邊的比基準點小,就繼續循序 while(arr[left]<=key&&left<right) { left++; } //交換基準點 arr[right]=arr[left]; } //最後給基準點賦值 arr[left]=key; return left; } }
注意:瞭解快速排序有助於瞭解MR的map-reduce過程,由於在MRmap階段環形緩衝區滿了以後,會將數據溢寫到文件中,這個過程當中就是使用了快速排序。ide
原理:對一個已有數組進行排序,那麼就新建一個數組,數組長度爲數組中元素的最大值+1。並把已有數組中的元素,對應上新建數組的下標,放入裏面,新建數組的元素爲,已有數組中元素的出現次數。
原理圖:
解釋:新建立一個數組,長度爲須要排序的數組的最大值+1,遍歷數組,將數組中的值分別找到新數組的索引,將索引處的元素+1,最後,遍歷輸出新數組的下標(只輸出相應的值>0的下標,而且值爲多少就輸出幾回)。
代碼實現:大數據
public class CountSort { public static void main(String[] args) { int arr[]= {2,7,1,2,8,1,3,9,415,189,123}; sort(arr,415); System.out.println(Arrays.toString(arr)); } public static void sort(int arr[],int max) { int index=0; int newarr[]=new int [max+1]; for(int i=0;i<arr.length;i++) { newarr[arr[i]]++; } for(int i=0;i<newarr.length;i++) { if(newarr[i]!=0) { for(int j=0;j<newarr[i];j++) { arr[index++]=i; } } } } }
注意:瞭解計數排序,有助於瞭解hbase的布隆過濾器,布隆過濾器的特色就是,我說沒有就沒有,我說有不必定有(有必定的誤判率)。ui
原理:針對多個有序的數據集進行排序。(時間複雜度:n*logN)
歸併排序有兩個階段:
一個是歸:將一個數據集拆分到每個小的數據集只有一個元素。
實現一個數據集的歸:3d
public static void chai(int arr[],int first,int last,int [] newarr) { if(first>=last) { return; } //找中間點 int mid=(first+last)/2; //左邊歸 chai(arr,first,mid,newarr); //右側拆 chai(arr,mid+1,last,newarr); //拆完以後並 meger(arr,first,last,mid,newarr); }
一個是並:將兩個有序的數據集,合併成爲一個有序的大數據集。
實現兩個有序數據集的並:
public int[] bing(int arr1[], int arr2[]) { //建立一個最終結果的數組:長度爲arr1和arr2長度之和 int newarr[] = new int[arr1.length+arr2.length]; //新數組的元素標記 int index=0; //記錄arr1和arr2的下標 int arr1_index=0; int arr2_index=0; //只要有一個數組,遍歷結束,就中止循環 while(arr1_index<arr1.length&&arr2_index<arr2.length) { //進行判斷,將數據存儲在新數組中 if(arr1[arr1_index]<arr2[arr2_index]) { newarr[index++]=arr1[arr1_index++]; }else { newarr[index++]=arr2[arr2_index++]; } } //多是arr1沒有遍歷徹底 while(arr1_index<arr1.length) { newarr[index++]=arr1[arr1_index++]; } //多是arr2沒有遍歷徹底 while(arr2_index<arr2.length) { newarr[index++]=arr2[arr2_index++]; } return newarr; }
完整代碼實現:
public class bingSort { public static void main(String[] args) { int arr[]= {1,8,7,6,11,2,4}; int newarr[]=new int[arr.length]; System.out.println(Arrays.toString(arr)); chai(arr,0,arr.length-1,newarr); System.out.println(Arrays.toString(newarr)); } //歸 public static void chai(int arr[],int first,int last,int [] newarr) { if(first>=last) { return; } //找中間點 int mid=(first+last)/2; //左邊歸 chai(arr,first,mid,newarr); //右側拆 chai(arr,mid+1,last,newarr); //拆完以後並 meger(arr,first,last,mid,newarr); } /** * 並 * @param arr 原數組 * @param first 開始位置 * @param last 結束位置 * @param mid 中間位置 * @param newarr 存放最終結果的數組 */ public static void meger(int arr[],int first,int last,int mid,int [] newarr) { //第一個數據集的起始下標 int arr1_start=first; //第一個數據集的終止下標 int arr1_end=mid; //第二個數據集的起始下標 int arr2_start=mid+1; //第二個數據集的終止下標 int arr2_end=last; int index=0; while(arr1_start<=arr1_end&&arr2_start<=arr2_end) { if(arr[arr1_start]<arr[arr2_start]) { newarr[index++]=arr[arr1_start++]; }else { newarr[index++]=arr[arr2_start++]; } } while(arr1_start<=arr1_end) { newarr[index++]=arr[arr1_start++]; } while(arr2_start<=arr2_end) { newarr[index++]=arr[arr2_start++]; } /** * 由於歸併排序,須要使用兩個有序的數據集,而arr一開始時無需的,全部每一次歸併的時候 * 須要將歸併好以後的那一段數據集,賦值到arr中,使以後的歸併仍然有序 */ //賦值的循環的次數,是本次歸併的元素的個數 for(int i=0;i<index;i++) { //每次賦值的時候,是從first開始 arr[first+i]=newarr[i]; } } }
注意:在MR程序中,其中有兩個階段使用到了歸併,一個是在緩衝區溢寫小文件時,最後會將多個小文件歸併成一個大文件,另外一個則是在reduce拉去map處理的數據到本地是會生成不少小文件,此時也會作一次歸併。
原理:在已經排好序的基礎上,將數組元素折半查找。
原理圖:
代碼實現:
public static void main(String[] args) { int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; // 二分法查數據 int num = new Scanner(System.in).nextInt(); //查找的數 int start = 0; int end = arr.length - 1; int middle = (start + end) / 2; while (true) { //若是end<start說明所有找完也沒有找到 if (end < start) { System.out.println(num + "不在此數組中"); break; } if (arr[middle] > num) { end = middle - 1; } else if (arr[middle] < num) { start = middle + 1; } else { System.out.println("這個數的索引下標爲" + middle); break; } middle = (start + end) / 2; }