Java實現面試六個算法

查找算法

典型的二分查找
對於二分查找算法要求, 查找前的數據必須是已經排好序的, 然後得到數組的開始位置start和結束位置end, 取中間位置mid的數據a[mid]跟待查找數據key進行比較, 若 a[mid] > key, 則取end = mid - 1; 若 a[mid] < key, 則取start = mid + 1; 若 a[mid] = key 則直接返回當前mid爲查找到的位置. 依次遍歷直到找到數據或者最終沒有該條數據. 囉嗦這麼多, 上代碼!!!

//已經排好序的數組public static int binarySearch(int[] nums, int key) {
    int start = 0;
    int end = nums.length - 1;
    int mid = -1;
    while (start <= end) {
        mid = (start + end) / 2;
        if (nums[mid] == key) {
            return mid;//已經查到返回!
        } else if (nums[mid] > key) {
            end = mid - 1;
        } else if (nums[mid] < key) {
            start = mid + 1;
        }
    }
    return -1;
}

排序算法

排序算法可以說是老生常談的問題, 下面的代碼思路是根據 嚴蔚敏的《數據結構》而來.
務必注意: 以下所有的排序算法都是從1開始, 而不是從0開始, 有的排序算法會把0位置當作監視哨
今天就介紹一下幾種常見的排序算法:

排序之前先寫一個交換方法後面會用到

  //交換
  private static void swap(int[] a, int i, int j) {
      a[i] ^= a[j];
      a[j] ^= a[i];
      a[i] ^= a[j];
  }


插入排序

插入排序的基本思想是,經過i-1遍處理後,L[1..i-1]己排好序。第i遍處理僅將L[i]插入L[1..i-1]的適當位置,使得L[1..i] 又是排好序的序列。要達到這個目的,我們可以用順序比較的方法。首先比較L[i]和L[i-1],如果L[i-1]≤ L[i],則L[1..i]已排好序,第i遍處理就結束了;否則交換L[i]與L[i-1]的位置,繼續比較L[i-1]和L[i-2],直到找到某一個位置j(1≤j≤i-1),使得L[j] ≤L[j+1]時爲止。圖1演示了對4個元素進行插入排序的過程,共需要(a),(b),(c)三次插入

穩定,時間複雜度 O(n^2)

//插入排序public static void insertSort(int[] a) {//a0爲監視哨位置,不作爲數據存儲
    int len = a.length;
    for (int i = 2; i < len; i++) {
        if (a[i - 1] > a[i]) {
            a[0] = a[i];
            a[i] = a[i - 1];
            int j = 0;
            for (j = i - 2; a[j] > a[0]; j--) {
                a[j + 1] = a[j];
            }
            a[j + 1] = a[0];
        }
    }
}

選擇排序

選擇排序的基本思想是對待排序的記錄序列進行n-1遍的處理,第i遍處理是將L[i..n]中最小者與L[i]交換位置。這樣,經過i遍處理之後,前i個記錄的位置已經是正確的了。

不穩定, 時間複雜度 O(n^2)

//選擇排序
public static void selectSort(int[] a) {
    for (int i = 1; i < a.length; i++) {
        int j = selectMinKey(a, i); //從i開始a.length中找到最小的位置
        if (i != j) {
            swap(a, i, j);
        }
    }
}

// 查找從i開始到a.length中最小的位置
private static int selectMinKey(int[] a, int i) {
    int key = i;
    for (int j = i + 1; j < a.length; j++) {
        if (a[j] < a[key]) {
            key = j;
        }
    }
    return key;
}

冒泡排序

冒泡排序方法是最簡單的排序方法。這種方法的基本思想是,將待排序的元素看作是豎着排列的“氣泡”,較小的元素比較輕,從而要往上浮。在冒泡排序算法中我們要對這個“氣泡”序列處理若干遍。所謂一遍處理,就是自底向上檢查一遍這個序列,並時刻注意兩個相鄰的元素的順序是否正確。如果發現兩個相鄰元素的順序不對,即“輕”的元素在下面,就交換它們的位置。顯然,處理一遍之後,“最輕”的元素就浮到了最高位置;處理二遍之後,“次輕”的元素就浮到了次高位置。在作第二遍處理時,由於最高位置上的元素已是“最輕”元素,所以不必檢查。一般地,第i遍處理時,不必檢查第i高位置以上的元素,因爲經過前面i-1遍的處理,它們已正確地排好序。

穩定,時間複雜度 O(n^2)

//冒泡排序
public static void bubbleSort(int[] a) {
    int len = a.length;
    for (int i = 1; i < len - 1; i++) {
        for (int j = i; j < len - i; j++) {
            if (a[j + 1] < a[j]) {
                swap(a, j + 1, j);
            }
        }
    }
}

快速排序

不穩定,時間複雜度 最理想 O(nlogn) 最差時間O(n^2)

快速排序是對冒泡排序的一種本質改進。它的基本思想是通過一趟掃描後,使得排序序列的長度能大幅度地減少。在冒泡排序中,一次掃描只能確保最大數值的數移到正確位置,而待排序序列的長度可能只減少1。快速排序通過一趟掃描,就能確保某個數(以它爲基準點吧)的左邊各數都比它小,右邊各數都比它大。然後又用同樣的方法處理它左右兩邊的數,直到基準點的左右只有一個元素爲止。

  //快速排序
  public static void quickSort(int[] a, int low, int high) {
      //遞歸快速排序
      int pivotLoc = 0;//中心點
      if (low < high) {
          pivotLoc = partitionLoc(a, low, high);
          quickSort(a, low, pivotLoc-1);
          quickSort(a, pivotLoc+1, high);
      }
  }

  //獲取到a的下標 low ~ high 中, a[low]的應該放的位置, 即左邊的數 < a[low] 右邊的數 > a[low]
  private static int partitionLoc(int[] a, int low, int high) {
      a[0] = a[low];
      while (low < high) {
          while (low < high && a[high] >= a[0]) {
              high--;
          }
          a[low] = a[high];
          while (low < high && a[low] <= a[0]) {
              low++;
          }
          a[high] = a[low];
      }
      a[low] = a[0];
      return low;
  }


Note: 在這裏就屬快速排序稍微有些複雜, 但是這也是常考一個算法, 仔細看代碼中的註釋應該能明白, 一起加油.
發佈了171 篇原創文章 · 獲贊 287 · 訪問量 99萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章