算法之旅(二) 初識數(shù)據(jù)結構與算法復雜度

一、常用數(shù)據(jù)結構概覽

  1. 數(shù)組(Array)
  2. 鏈表(Linked List)
  3. 棧(Stack)
  4. 隊列(Queue)
  5. 哈希表(Hash Table)
  6. 樹(Tree)
  7. 圖(Graph)
  8. 堆(Heap)
  9. 集合(Set)
  10. 字典樹(Trie)

二、數(shù)據(jù)結構的詳細介紹

1. 數(shù)組(Array)

  • 特點

    • 連續(xù)內存分配:數(shù)組中的元素在內存中連續(xù)存儲。
    • 固定大小:數(shù)組的大小在初始化后不能改變。
    • 快速訪問:可以通過索引快速訪問元素,時間復雜度為 O(1)。
  • 適用場景

    • 需要快速隨機訪問元素的場景。
  • 示例代碼

    int[] numbers = new int[5];
    numbers[0] = 10;
    int firstNumber = numbers[0]; // O(1) 訪問
    

2. 鏈表(Linked List)

  • 特點

    • 動態(tài)大小:可以隨時增加或刪除元素。
    • 節(jié)點結構:由節(jié)點組成,每個節(jié)點包含數(shù)據(jù)和指向下一個節(jié)點的引用。
    • 順序訪問:訪問元素需要從頭節(jié)點開始,時間復雜度為 O(n)。
  • 分類

    • 單向鏈表:每個節(jié)點指向下一個節(jié)點。
    • 雙向鏈表:每個節(jié)點有指向前一個和后一個節(jié)點的引用。
  • 適用場景

    • 需要頻繁插入和刪除元素的場景。
  • 示例代碼

    class Node {
        int data;
        Node next;
        Node(int data) {
            this.data = data;
        }
    }
    
    // 創(chuàng)建鏈表
    Node head = new Node(10);
    head.next = new Node(20);
    

3. 棧(Stack)

  • 特點

    • 后進先出(LIFO):最后入棧的元素最先出棧。
  • 常用操作

    • push:入棧,時間復雜度 O(1)。
    • pop:出棧,時間復雜度 O(1)。
  • 適用場景

    • 處理遞歸、表達式求值、瀏覽器歷史記錄等。
  • 示例代碼

    Stack<Integer> stack = new Stack<>();
    stack.push(10);
    int top = stack.pop(); // O(1)
    

4. 隊列(Queue)

  • 特點

    • 先進先出(FIFO):最先入隊的元素最先出隊。
  • 常用操作

    • enqueue:入隊,時間復雜度 O(1)。
    • dequeue:出隊,時間復雜度 O(1)。
  • 適用場景

    • 任務調度、廣度優(yōu)先搜索等。
  • 示例代碼

    Queue<Integer> queue = new LinkedList<>();
    queue.add(10);
    int first = queue.poll(); // O(1)
    

5. 哈希表(Hash Table)

  • 特點

    • 鍵值對存儲:通過鍵(Key)訪問對應的值(Value)。
    • 快速查找:平均情況下,插入、刪除、查找的時間復雜度為 O(1)。
  • 適用場景

    • 需要快速插入、刪除、查找的場景。
  • 示例代碼

    Map<String, Integer> map = new HashMap<>();
    map.put("apple", 3);
    int count = map.get("apple"); // O(1)
    

6. 樹(Tree)

  • 特點

    • 層次結構:由節(jié)點和邊組成的分層數(shù)據(jù)結構。
  • 分類

    • 二叉樹:每個節(jié)點最多有兩個子節(jié)點。
    • 二叉搜索樹(BST):左子節(jié)點小于父節(jié)點,右子節(jié)點大于父節(jié)點。
    • 平衡樹:如紅黑樹、AVL樹,保持樹的平衡性。
  • 適用場景

    • 實現(xiàn)高效的查找、排序、范圍查詢等。
  • 示例代碼

    class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode(int x) { val = x; }
    }
    
    // 創(chuàng)建二叉樹節(jié)點
    TreeNode root = new TreeNode(10);
    root.left = new TreeNode(5);
    root.right = new TreeNode(15);
    

7. 圖(Graph)

  • 特點

    • 節(jié)點(頂點)和邊:表示物體和它們之間的關系。
  • 表示方法

    • 鄰接矩陣:二維數(shù)組表示節(jié)點之間的連接。
    • 鄰接表:每個節(jié)點的鄰居列表。
  • 適用場景

    • 社交網(wǎng)絡、地圖導航、任務調度等。
  • 示例代碼

    // 使用鄰接表表示圖
    Map<String, List<String>> graph = new HashMap<>();
    graph.put("A", Arrays.asList("B", "C"));
    graph.put("B", Arrays.asList("A", "D"));
    

8. 堆(Heap)

  • 特點

    • 完全二叉樹:所有節(jié)點都滿足堆的性質。
    • 大頂堆:每個父節(jié)點的值都大于等于其子節(jié)點。
    • 小頂堆:每個父節(jié)點的值都小于等于其子節(jié)點。
  • 適用場景

    • 實現(xiàn)優(yōu)先隊列、排序(堆排序)、求解 Top K 問題等。
  • 示例代碼

    // 小頂堆
    PriorityQueue<Integer> minHeap = new PriorityQueue<>();
    minHeap.add(5);
    minHeap.add(2);
    int smallest = minHeap.poll(); // 2
    

9. 集合(Set)

  • 特點

    • 元素唯一性:不包含重復元素。
  • 適用場景

    • 去重操作、集合運算(交集、并集、差集)等。
  • 示例代碼

    Set<String> set = new HashSet<>();
    set.add("apple");
    set.add("banana");
    boolean exists = set.contains("apple"); // true
    

10. 字典樹(Trie)

  • 特點

    • 前綴樹:用于高效地存儲和檢索字符串集合,尤其是字符串前綴共享的集合。
  • 適用場景

    • 自動補全、拼寫檢查、前綴查詢等。
  • 示例代碼

    class TrieNode {
        boolean isWord;
        Map<Character, TrieNode> children = new HashMap<>();
        TrieNode() {
            isWord = false;
        }
    }
    
    // 插入單詞
    void insert(TrieNode root, String word) {
        TrieNode node = root;
        for (char c : word.toCharArray()) {
            node.children.putIfAbsent(c, new TrieNode());
            node = node.children.get(c);
        }
        node.isWord = true;
    }
    

三、算法復雜度

算法復雜度用于評估算法的性能,主要分為時間復雜度空間復雜度。

1. 時間復雜度(Time Complexity)

  • 定義:算法執(zhí)行所需時間與輸入規(guī)模之間的函數(shù)關系。

常見時間復雜度類型及示例

  1. O(1) - 常數(shù)時間復雜度

    • 描述:算法的執(zhí)行時間不隨輸入規(guī)模變化。

    • 示例:訪問數(shù)組中的某個元素。

      int getFirstElement(int[] arr) {
          return arr[0]; // O(1)
      }
      
  2. O(log n) - 對數(shù)時間復雜度

    • 描述:算法的執(zhí)行時間隨輸入規(guī)模的對數(shù)增長。

    • 示例:二分查找。

      int binarySearch(int[] arr, int target) {
          int left = 0, right = arr.length -1;
          while (left <= right) {
              int mid = left + (right - left) / 2;
              if (arr[mid] == target) {
                  return mid; // O(log n)
              } else if (arr[mid] < target) {
                  left = mid + 1;
              } else {
                  right = mid -1;
              }
          }
          return -1;
      }
      
  3. O(n) - 線性時間復雜度

    • 描述:算法的執(zhí)行時間與輸入規(guī)模成正比。

    • 示例:遍歷數(shù)組。

      int sumArray(int[] arr) {
          int sum = 0;
          for (int num : arr) {
              sum += num; // O(n)
          }
          return sum;
      }
      
  4. O(n log n) - 線性對數(shù)時間復雜度

    • 描述:常見于高效排序算法,如歸并排序、快速排序。

    • 示例:歸并排序。

      void mergeSort(int[] arr, int left, int right) {
          if (left < right) {
              int mid = (left + right) / 2;
              mergeSort(arr, left, mid);       // O(log n)
              mergeSort(arr, mid + 1, right);  // O(log n)
              merge(arr, left, mid, right);    // O(n)
          }
      }
      
  5. O(n2) - 二次時間復雜度

    • 描述:算法的執(zhí)行時間與輸入規(guī)模的平方成正比。

    • 示例:冒泡排序。

      void bubbleSort(int[] arr) {
          int n = arr.length;
          for (int i = 0; i < n - 1; i++) {           // O(n)
              for (int j = 0; j < n - i - 1; j++) {   // O(n)
                  if (arr[j] > arr[j +1]) {
                      // 交換
                      int temp = arr[j];
                      arr[j] = arr[j +1];
                      arr[j +1] = temp;
                  }
              }
          }
      }
      

時間復雜度優(yōu)先級排行(從高效到低效)

  1. O(1) - 常數(shù)時間
  2. O(log n) - 對數(shù)時間
  3. O(n) - 線性時間
  4. O(n log n) - 線性對數(shù)時間
  5. O(n2) - 二次時間
  6. O(2?) - 指數(shù)時間
  7. O(n!) - 階乘時間

2. 空間復雜度(Space Complexity)

  • 定義:算法執(zhí)行過程中所需的額外空間與輸入規(guī)模之間的函數(shù)關系。

常見空間復雜度類型及示例

  1. O(1) - 常數(shù)空間復雜度

    • 描述:算法所需的額外空間不隨輸入規(guī)模變化。

    • 示例:在原地交換兩個變量。

      void swap(int[] arr, int i, int j) {
          int temp = arr[i];
          arr[i] = arr[j];
          arr[j] = temp;
          // O(1) 空間
      }
      
  2. O(n) - 線性空間復雜度

    • 描述:算法所需的額外空間與輸入規(guī)模成正比。

    • 示例:創(chuàng)建一個新數(shù)組存儲輸入數(shù)組的副本。

      int[] copyArray(int[] arr) {
          int n = arr.length;
          int[] newArr = new int[n]; // O(n) 空間
          for (int i = 0; i < n; i++) {
              newArr[i] = arr[i];
          }
          return newArr;
      }
      
  3. O(n2) - 二次空間復雜度

    • 描述:算法所需的額外空間與輸入規(guī)模的平方成正比。

    • 示例:創(chuàng)建一個二維矩陣。

      int[][] matrix = new int[n][n]; // O(n2) 空間
      

空間復雜度優(yōu)先級排行(從高效到低效)

  1. O(1) - 常數(shù)空間
  2. O(log n) - 對數(shù)空間(通常出現(xiàn)在遞歸調用的??臻g中)
  3. O(n) - 線性空間
  4. O(n log n)
  5. O(n2) - 二次空間

四、復雜度優(yōu)先級總結

  • 時間復雜度優(yōu)先級(從高效到低效)

    1. O(1)
    2. O(log n)
    3. O(n)
    4. O(n log n)
    5. O(n2)
    6. O(2?)
    7. O(n!)
  • 空間復雜度優(yōu)先級(從高效到低效)

    1. O(1)
    2. O(log n)
    3. O(n)
    4. O(n log n)
    5. O(n2)

  • 數(shù)據(jù)結構:選擇合適的數(shù)據(jù)結構對于算法的效率至關重要。先了解所有常用的數(shù)據(jù)結構,然后深入理解其特點、操作和適用場景。

  • 算法復雜度:時間復雜度和空間復雜度是衡量算法性能的兩個重要指標。了解各種復雜度類型及其優(yōu)先級,有助于在開發(fā)中選擇最優(yōu)的算法和數(shù)據(jù)結構。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
禁止轉載,如需轉載請通過簡信或評論聯(lián)系作者。

相關閱讀更多精彩內容

友情鏈接更多精彩內容