C/C++ 常用的四種查找算法

在計算機科學中,搜索算法是一種用於在數據集合中查找特定元素的算法。C語言作爲一種強大的編程語言,提供了多種搜索算法的實現方式。本文將介紹C語言中的四種常見搜索算法其中包括(線性查找,二分法查找,樹結構查找,分塊查找),並提供每種算法的簡單實現示例。

常見的查找算法主要有以下幾種:

  1. 線性查找(Linear Search):
    • 簡單直觀,適用於無序列表。
    • 從列表的一端開始逐個元素比較,直到找到目標元素或遍歷完整個列表。
  2. 二分查找(Binary Search):
    • 適用於有序列表。
    • 每次將目標值與中間元素比較,可以迅速縮小搜索範圍。
  3. 樹結構查找(樹的各種形式,如二叉搜索樹、AVL樹、紅黑樹等):
    • 通過樹結構,可以更加高效地進行查找、插入和刪除操作。
    • 二叉搜索樹要求左子樹上所有結點的值小於根結點的值,右子樹上所有結點的值大於根結點的值。
  4. 分塊查找(Block Search):
    • 將數據分成若干塊,每一塊中的元素無序,但塊與塊之間有序。
    • 先確定目標元素所在的塊,再在塊內進行線性查找。

這些查找算法各自有適用的場景和優勢,選擇合適的查找算法取決於數據的特性以及實際應用的需求。

線性搜索,又稱爲順序搜索(Sequential Search),是一種簡單直觀的查找算法。該算法通過順序遍歷數據集,逐一比較每個元素與目標值是否相等,直到找到目標值或遍歷完整個數據集。

算法步驟

  1. 從頭到尾遍歷數據集: 從數據集的第一個元素開始,依次比較每個元素與目標值是否相等。
  2. 比較目標值: 對於每個元素,與目標值進行比較。
  3. 找到目標值: 如果找到了與目標值相等的元素,返回該元素的位置或索引。
  4. 遍歷完整個數據集: 如果遍歷完整個數據集仍未找到目標值,返回未找到的標記(通常是一個特殊值,如-1)。

特點

  1. 適用於小型數據集: 線性搜索適用於小型數據集,對於大型數據集可能效率較低。
  2. 無序數據: 不依賴數據的排列順序,適用於無序數據。
  3. 簡單直觀: 實現簡單,易於理解。

線性搜索是最簡單的搜索算法之一,它按順序遍歷數據集合,查找目標元素。以下是一個線性搜索的C語言示例:

#include <stdio.h>

int linearSearch(int arr[], int n, int target)
{
    for (int i = 0; i < n; i++)
    {
        if (arr[i] == target)
        {
            return i; // 找到則返回索引
        }
    }
    return -1; // 未找到則返回-1
}

int main(int argc, char *argv[])
{
    int arr[] = {1, 2, 3, 4, 5};
    int n = sizeof(arr) / sizeof(arr[0]);
    int target = 3;
    int result = linearSearch(arr, n, target);
    if (result != -1)
    {
        printf("元素在索引 %d 處找到\n", result);
    } else
    {
        printf("未找到元素\n");
    }
    return 0;
}

二分搜索(Binary Search)是一種在有序數組中查找目標值的算法。它通過反覆將查找範圍劃分爲兩半並比較目標值與中間元素的大小,從而縮小搜索範圍,直到找到目標值或確定目標值不存在。

算法步驟

  1. 初始化: 確定搜索範圍的起始點 left 和終止點 right
  2. 循環條件:left 小於等於 right 時執行循環。
  3. 計算中間位置: 計算中間位置 midmid = (left + right) / 2
  4. 比較目標值: 將目標值與中間元素進行比較。
    • 如果目標值等於中間元素,找到目標,返回索引。
    • 如果目標值小於中間元素,說明目標值在左半部分,更新 right = mid - 1
    • 如果目標值大於中間元素,說明目標值在右半部分,更新 left = mid + 1
  5. 循環結束:left 大於 right,表示搜索範圍爲空,未找到目標值。

特點

  1. 有序數組: 二分搜索要求數組是有序的,以便通過比較中間元素確定目標值在哪一半。
  2. 高效性: 由於每一步都將搜索範圍縮小一半,因此二分搜索的平均時間複雜度爲 O(log n)。
  3. 適用性: 適用於靜態數據集或很少變化的數據集,不適用於頻繁插入、刪除操作的動態數據集。

二分搜索要求數據集合是有序的,以下是一個二分搜索的C語言示例:

#include <stdio.h>

int binary_search(int key, int a[], int n)
{
  int low, high, mid, count = 0, count1 = 0;
  low = 0;
  high = n - 1;
  while (low<high)
  {
    count++;                    // 記錄查找次數
    mid = (low + high) / 2;     // 求出中間位置
    if (key<a[mid])             // 當key小於中間值
      high = mid - 1;         // 確定左子表範圍
    else if (key>a[mid])        // 當key大於中間值
      low = mid + 1;          // 確定右子表範圍
    else if (key == a[mid])     // 當key等於中間值證明查找成功
    {
      printf("查找元素: %d Array[%d]=%d\n", count, mid, key);
      count1++;            //count1記錄查找成功次數
      break;
    }
  }
  if (count1 == 0)
    return 0;
}

int main(int argc, char *argv[])
{
  int number = 10, key = 6;
  int Array[10] = { 1, 5, 6, 7, 9, 3, 4, 6, 0, 2 };

  binary_search(key, Array, number);

  return 0;
}

二叉搜索樹 (BST)

二叉搜索樹(Binary Search Tree,BST)是一種二叉樹數據結構,其中每個節點都有一個鍵值,且滿足以下性質:

  1. 對於樹中的每個節點,其左子樹中的所有節點的鍵值都小於該節點的鍵值。
  2. 對於樹中的每個節點,其右子樹中的所有節點的鍵值都大於該節點的鍵值。
  3. 左、右子樹也分別爲二叉搜索樹。

這個性質使得在二叉搜索樹中可以高效地進行搜索、插入和刪除操作。

特點

  1. 有序性: 由於BST的定義,其中的元素是有序排列的。對於任意節點,其左子樹的值小於該節點,右子樹的值大於該節點,因此通過中序遍歷BST可以得到有序的元素序列。
  2. 高效的搜索操作: 由於有序性,可以通過比較鍵值快速定位目標節點,使搜索操作的平均時間複雜度爲 O(log n)。在最壞情況下(樹退化爲鏈表),搜索的時間複雜度爲 O(n)。
  3. 高效的插入和刪除操作: 插入和刪除操作也涉及到比較鍵值和調整樹的結構,平均情況下的時間複雜度爲 O(log n)。在最壞情況下,樹可能變得不平衡,導致時間複雜度爲 O(n),但通過平衡二叉搜索樹(如 AVL 樹、紅黑樹等)可以保持樹的平衡。

操作

  1. 搜索(Search): 從根節點開始比較目標值,根據比較結果選擇左子樹或右子樹,直到找到目標節點或達到葉子節點。
  2. 插入(Insert): 從根節點開始,按照比較結果選擇左子樹或右子樹,直到找到合適的插入位置,插入新節點。
  3. 刪除(Delete): 找到要刪除的節點,可能有以下幾種情況:
    • 若該節點爲葉子節點,直接刪除。
    • 若該節點有一個子節點,用子節點替代該節點。
    • 若該節點有兩個子節點,找到右子樹中的最小節點或左子樹中的最大節點,替代該節點,並遞歸刪除被替代的節點。

以下是一個簡化的BST的C語言示例:

#include <stdio.h>
#include <stdlib.h>

struct Node
{
    int key;
    struct Node *left, *right;
};

struct Node* newNode(int key)
{
    struct Node* node = (struct Node*)malloc(sizeof(struct Node));
    node->key = key;
    node->left = node->right = NULL;
    return node;
}

struct Node* insert(struct Node* root, int key)
{
    if (root == NULL)
        return newNode(key);
    if (key < root->key)
        root->left = insert(root->left, key);
    else if (key > root->key)
        root->right = insert(root->right, key);
    return root;
}

int main(int argc, char *argv[])
{
    struct Node* root = NULL;
    int keys[] = {3, 1, 5, 2, 4};
    for (int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++)
    {
        root = insert(root, keys[i]);
    }
    // 可以在 'root' 上執行BST操作
    return 0;
}

分塊搜索(Block Search)是一種在查找大量數據中的目標值時,將數據分成若干塊,然後在塊內進行查找的策略。這種方法適用於一些動態更新頻繁,但每次更新數據量較小的場景。

算法步驟

  1. 數據分塊: 將大量數據按照一定的規則分成若干塊。
  2. 建立索引表: 對每個塊建立索引,記錄每塊的起始位置、結束位置和關鍵字(通常是塊內最大的關鍵字)。
  3. 查找塊: 根據目標值的大小確定它可能在哪個塊中,找到相應的塊。
  4. 在塊內查找: 在確定的塊內使用線性查找或其他查找算法尋找目標值。

特點

  1. 適用於動態數據: 分塊搜索適用於數據集動態更新的情況,因爲每次更新數據只需更新相應塊的索引。
  2. 索引表: 建立索引表有助於快速定位目標值可能存在的塊,提高查找效率。
  3. 非均勻分塊: 可以根據數據的特點進行非均勻分塊,以適應不同數據分佈情況。

該查找與二分查找類似,都是對半分,分塊則可以分爲多塊,效率更高一些。如下這段C語言代碼實現了分塊查找算法。分塊查找是一種基於塊的數據結構的搜索算法,通過將數據集劃分爲若干塊(或稱爲塊),併爲每個塊建立一個索引。每個索引記錄了該塊的起始位置、結束位置以及該塊內元素的最大值。

#include <stdio.h>

struct index           //定義塊的結構
{
  int key;
  int start;
  int end;
}index_table[4];       //定義結構體數組

int block_search(int key, int a[])          //自定義實現分塊查找
{
  int i, j;
  i = 1;
  while (i <= 3 && key>index_table[i].key)      //確定在哪個塊中
    i++;
  if (i>3)                                  //大於分得的塊數,則返回0
    return 0;
  j = index_table[i].start;                  //j等於塊範圍的起始值
  while (j <= index_table[i].end&&a[j] != key)  //在確定的塊內進行查找
    j++;
  if (j>index_table[i].end)    //如果大於塊範圍的結束值,則說明沒有要查找的數
    j = 0;
  return j;
}

int main(int argc, char *argv[])
{
  int x, y = 0,ref = 0;
  int key = 8;
  int Array[16] = { 1, 3, 4, 5, 6, 7, 8, 9, 0, 4, 3, 5, 6, 7, 8, 9 };

  for (x = 1; x <= 3; x++)
  {
    index_table[x].start = y + 1;       // 確定每個範圍的起始行
    y = y + 1;
    index_table[x].end = y + 4;         // 確定每個塊範圍的結束值
    y = y + 4;
    index_table[x].key = Array[y];      // 確定每個塊範圍中元素的最大值
  }

  ref = block_search(key, Array);
  if (ref != 0)
  {
    printf("position is: %d \n", ref);
  }
  return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章