Java的數據結構和算法

Java的數據結構

1、Collection

Collection接口有List和Set兩個子接口。算法

一、List

  • ArrayList
    • 底層動態數據結構,可存儲重複元素,存儲有序。
    • 線程不安全的,效率高。
    • 初始化一個ArrayList時,不指定容量,默認會建立一個容量10的數組。隨着添加元素,達到數組容量上限時,可自動擴容一倍的容量。
    • 查詢快,增刪慢。底層動態數組,數組的元素在內存中地址是連續的。查詢時可直接經過數組索引找到結果。增刪時,因爲是對數組操做,每增長或刪除元素,數組內全部的元素內存地址都會變更,會比較慢。
  • LinkedList
    • 底層雙向鏈表數據結構,可存儲重複元素,存儲有序。
    • 鏈表上的節點是一個Node,Node中item是當前節點的值,prev指向上一節點,next指向下一節點。
    • 查詢慢,增刪快。由於LindedList底層實現是鏈表,鏈表的每一個節點在內存中的存儲地址是隨機非連續的,節點除了記錄本身的值還要記錄下一個節點甚至上一個節點的指針。查詢時只能遍歷鏈表,equals比較值,找到結果,會比較慢。增長元素,只須要在鏈表末尾新增一個節點,並將上一個節點的next指針指向新增的節點便可。刪除元素,先遍歷鏈表插到要刪除的節點,而後置空此節點,將先後節點的指針關聯起來。
  • Vector
    • 和ArrayList特性基本類似,線程安全的,效率低。
    • 還有個子類Stack,通常可用於棧的管理。push方法添加一個對象到棧頂,pop方法彈出棧頂的對象,peek方法查看棧頂的對象。

二、Set

  • HashSet
    • 基於HashMap實現,HashSet的值就是HashMap的key,value是PRESENT對象。
    • 不可存儲重複元素,存儲無序。
  • TreeSet
    • 底層紅黑樹數據結構。
    • 不可存儲重複元素,存儲有序。有基於元素key的高效排序算法,存儲順序從小到大。

2、Map

  • HashMap
    • 線程不安全的,效率略高,集中了ArrayList和LinkedList的優勢。
    • 存儲無需,key值惟一,可存儲一組null。
    • HashMap底層是一個hash表,元素爲單項鍊表的數組,jdk1.8以前數據的元素是鏈表,jdk1.8以後,若鏈表長度達到8時,則會將鏈表置換爲紅黑樹。
    • 初始化HashMap時,若不傳入容量,默認會生成長度16,加載因子0.75的數組。隨着數組存儲長度達到16*0.75時,會自動擴容一倍的容量。
    • HashMap中,是以鍵值對的形式存儲,經過key的hashcode值,決定該組鍵值對在數組的具體位置,而後找到對應的單鏈表。每組鍵值對,jdk1.8以前封裝成Entry,jdk1.8以後封裝成了Node,Node中包含key的hash值,key值,value值,下一個節點的指針。
    • HashMap當put鍵值對時,首先算出key的hashcode值,去遍歷數組找對應的下標,找不到,則會在數組末尾添加一組,保存該節點。找到了對應下標後,則會遍歷這個位置的鏈表,根據key值判斷是否已有節點,有的話直接用新值覆蓋掉舊值,若沒有節點,在鏈表的末尾保存該節點。
    • 之因此使用單鏈表存儲,是由於存儲的鍵值對愈來愈多,就有可能出現key生成的hashcode同樣,形成hash衝突,此時,便可把新添加的鍵值對存在這個數組位置對應的單鏈表內。單鏈表裏的每一個節點,key的hashcode是相同的,可是key值不一樣,他們在數組的同一個索引位置。
  • TreeMap
    • 有序的key-value集合,基於紅黑樹實現,不能存儲null。
    • 線程不安全的。
  • Hashtable
    • 和HashMap功能基本類似。
    • 但線程安全的,效率低。

Java基本算法、排序方式

  • 選擇排序:雙重for循環,每一趟排序獲取最小數,依次將最小數的位置放在已排好序的序列最後。
int[] arr = {6, 4, 9, 1, 5, 3};
for(int i = 0; i < arr.length - 1; i++) {
    int k = i;
    for(int j = k + 1; j < arr.length; j++) { // 選最小的值
        if(arr[j] < arr[k]) { 
            k = j; // 記下目前找到的最小值所在的位置
        }
    }
    // 找到本輪循環的最小的數之後,再進行交換
    if(i != k) { // 交換a[i]和a[k]
        int temp = arr[i];
        arr[i] = arr[k];
        arr[k] = temp;
    }
}
複製代碼
  • 冒泡排序:雙重for循環,依次比較相鄰的兩個元素,將小數放在前面,大數放在後面。
int[] arr = {6, 4, 9, 1, 5, 3};
int temp;
for(int i = 0; i < arr.length - 1; i++) { // 外層循環控制排序趟數
    for(int j = 0; j < arr.length - i - 1; j++) { // 內層循環控制每一趟排序多少次,每一次循環把大數滾到隊列末尾
        if(arr[j + 1] < arr[j]) {
            temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
        }
    }
}
複製代碼
  • 快速排序:選擇一個關鍵值做爲基準值。比基準值小的都在左邊序列,比基準值大的都在右邊序列。時間複雜度爲O(NlogN)。
public static int[] quickStore(int[] array, int l, int r) {
    if (l < r) {
        int i = l;
        int j = r;
        int x = array[l];
        while (i < j) {
            while (i < j && array[j] >= x) {
                // 從右向左找第一個小於x的數
                j--;
            }
            if (i < j) {
                array[i++] = array[j];
            }
            while (i < j && array[i] < x) { // 從左向右找第一個大於等於x的數
                i++;
            }
            if (i < j) {
                array[j--] = array[i];
            }
        }
        array[i] = x;
        quickStore(array, l, i - 1);
        quickStore(array, i + 1, r);
    }
    return array;
}
複製代碼
  • 二分查找法:對有序數列查找,查找時,先以有序數列的中點位置爲比較對象,若是要找的元素值小於該中點元素,則將待查序列縮小爲左半部分,不然爲右半部分。經過一次比較,將查找區間縮小一半。如此遞歸執行,直至查找到對象。
// 二分查找遞歸實現   
public static int binSearch(int array[], int start, int end, int key) {  
    int mid = (end - start) / 2 + start;
    if (array[mid] == key) {
        return mid;
    }
    if (start >= end) {
        return -1;
    } else if (key > array[mid]) {
        return binSearch(array, mid + 1, end, key);
    } else if (key < array[mid]) {
        return binSearch(array, start, mid - 1, key);
    }
    return -1; 
}

// 二分查找普通循環實現   
public static int binSearch(int array[], int key) {
    int mid = array.length / 2;   
    if (key == array[mid]) {
        return mid;
    }

    int start = 0;
    int end = array.length - 1;
    while (start <= end) {
        mid = (end - start) / 2 + start;
        if (key < array[mid]) {
           end = mid - 1;
        } else if (key > array[mid]) {
            start = mid + 1;
        } else {
            return mid;
        }
    }
    return -1;
}
複製代碼
相關文章
相關標籤/搜索