日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

tail -f 查找关键字_C语言九种查找算法 | 总有一款适合你

發布時間:2025/3/15 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 tail -f 查找关键字_C语言九种查找算法 | 总有一款适合你 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

時間、空間復雜度比較

查找算法平均時間復雜度空間復雜度查找條件
順序查找O(n)O(1)無序或有序
二分查找(折半查找)O(log2n)O(1)有序
插值查找O(log2(log2n))O(1)有序
斐波那契查找O(log2n)O(1)有序
哈希查找O(1)O(n)無序或有序
二叉查找樹(二叉搜索樹查找)O(log2n)
紅黑樹O(log2n)
2-3樹O(log2n - log3n)
B樹/B+樹O(log2n)

1 順序查找

算法思路

對于任意一個序列,從一端開始,順序掃描,依次將掃描到的結點關鍵字與給定值k相比較,若相等則表示查找成功;若掃描結束仍沒有找到關鍵字等于k的結點,表示查找失敗。

代碼

#include
#include
#define keyType int
//2020.05.24
typedef struct
{
keyType key;//查找表中每個數據元素的值
}ElemType;
typedef struct
{
ElemType *elem;//存放查找表中數據元素的數組
int length;//記錄查找表中數據的總數量
}SSTable;
//創建查詢數據
void Create(SSTable **st,int length)
{
(*st)=(SSTable*)malloc(sizeof(SSTable));
(*st)->length=length;
(*st)->elem =(ElemType*)malloc((length+1)*sizeof(ElemType));
printf("輸入表中的數據元素:\n");
//根據查找表中數據元素的總長度,在存儲時,從數組下標為 1 的空間開始存儲數據
for (int i=1; i<=length; i++)
{
scanf("%d",&((*st)->elem[i].key));
}
}
//順序查找函數,其中key為要查找的元素
int Search_seq(SSTable *str,keyType key)
{
//str->elem[0].key=key;//將關鍵字作為一個數據元素存放到查找表的第一個位置,起監視哨的作用
int len = str->length;
//從最后一個數據元素依次遍歷,一直遍歷到數組下標為0
for(int i=1; i {
if(str->elem[i].key == key)
{
return i;
}
}
//如果 i=0,說明查找失敗;查找成功返回要查找元素key的位置i
return 0;
}
int main()
{
SSTable *str;
int num;
printf("請輸入創建數據元素的個數:\n");
scanf("%d",&num);
Create(&str, num);
getchar();
printf("請輸入要查找的數據:\n");
int key;
scanf("%d",&key);
int location=Search_seq(str, key);
if (location==0) {
printf("查找失敗");
}else{
printf("要查找的%d的順序為:%d",key,location);
}
return 0;
}

運行結果

查找成功查找失敗

2 二分查找(折半查找)

算法思路

  • 確定查找范圍low=0,high=N-1,計算中項mid=(low+high)/2。

  • 若mid==x或low>=high,則結束查找;否則,向下繼續。

  • 若amidx,說明待查找的元素值只可能在比中項元素小的范圍內,則把mid-1的值賦給higt,并重新計算mid,轉去執行步驟2。

  • 說明

    • 查找元素必須是有序的,如果是無序的則要先進行排序操作。

    • 在做查找的過程中,如果 low 指針和 high 指針的中間位置在計算時位于兩個關鍵字中間,即求得 mid 的位置不是整數,需要統一做取整操作。

    折半查找的前提條件是需要有序表順序存儲,對于靜態查找表,一次排序后不再變化,折半查找能得到不錯的效率。但對于需要頻繁執行插入或刪除操作的數據集來說,維護有序的排序會帶來不小的工作量,那就不建議使用。

    ——《大話數據結構》

    代碼

    #include
    #include
    #define keyType int
    typedef struct
    {
    keyType key;//查找表中每個數據元素的值
    }ElemType;
    typedef struct
    {
    ElemType *elem;//存放查找表中數據元素的數組
    int length;//記錄查找表中數據的總數量
    }SSTable;
    //創建查詢數據
    void Create(SSTable **st,int length)
    {
    (*st)=(SSTable*)malloc(sizeof(SSTable));
    (*st)->length=length;
    (*st)->elem =(ElemType*)malloc((length+1)*sizeof(ElemType));
    printf("輸入表中的數據元素:\n");
    //根據查找表中數據元素的總長度,在存儲時,從數組下標為 1 的空間開始存儲數據
    for (int i=1; i<=length; i++)
    {
    scanf("%d",&((*st)->elem[i].key));
    }
    }
    //折半查找函數 key為要查找的元素
    int Search_Bin(SSTable *str,keyType key)
    {
    int low=1;//初始狀態 low 指針指向第一個關鍵字
    int high=str->length;//high 指向最后一個關鍵字
    int mid;
    while (low<=high)
    {
    mid=(low+high)/2;//int 本身為整形,所以,mid 每次為取整的整數
    if(str->elem[mid].key==key)//如果 mid 指向的同要查找的相等,返回 mid 所指向的位置
    {
    return mid;
    }
    else if(str->elem[mid].key>key)//如果mid指向的關鍵字較大,則更新 high 指針的位置
    {
    high=mid-1;
    }
    //反之,則更新 low 指針的位置
    else
    {
    low=mid+1;
    }
    }
    return 0;
    }
    int main()
    {
    SSTable *str;
    int num;
    printf("請輸入創建數據元素的個數:\n");
    scanf("%d",&num);
    Create(&str, num);
    getchar();
    printf("請輸入要查找的數據:\n");
    int key;
    scanf("%d",&key);
    int location=Search_Bin(str, key);
    if (location==0) {
    printf("沒有查找到");
    }else{
    printf("要查找的%d的順序為:%d",key,location);
    }
    return 0;
    }

    運行結果

    查找成功沒有查找到

    3 插值查找

    插值查找基于二分查找算法,將查找點的選擇改進為自適應選擇,可以提高查找效率。當然,差值查找也屬于有序查找

    算法思路

  • 確定查找范圍low=0,high=N-1,計算中項mid=low+(key-a[low])/(a[high]-a[low])*(high-low)。

  • 若mid==x或low>=high,則結束查找;否則,向下繼續。

  • 若amidx,說明待查找的元素值只可能在比中項元素小的范圍內,則把mid-1的值賦給higt,并重新計算mid,轉去執行步驟2。

  • 說明

    • 插值查找是基于折半查找進行了優化的查找方法。
    • 當表長較大,而關鍵字分布又比較均勻的查找表來說,插值查找算法的平均性能要比折半查找要好得多。

    代碼

    #include
    int array[10] = { 1, 4, 9, 16, 27, 31, 33, 35, 45, 64 };
    int InsertionSearch(int data)
    {
    int low = 0;
    int high = 10 - 1;
    int mid = -1;
    int comparisons = 1;
    int index = -1;
    while(low <= high)
    {
    printf("比較 %d 次\n" , comparisons );
    printf("low : %d, list[%d] = %d\n", low, low, array[low]);
    printf("high : %d, list[%d] = %d\n", high, high, array[high]);
    comparisons++;
    mid = low + (((double)(high - low) / (array[high] - array[low])) * (data - array[low]));
    printf("mid = %d\n",mid);
    // 沒有找到
    if(array[mid] == data)
    {
    index = mid;
    break;
    }
    else
    {
    if(array[mid] < data)
    {
    low = mid + 1;
    }
    else
    {
    high = mid - 1;
    }
    }
    }
    printf("比較次數: %d\n", --comparisons);
    return index;
    }
    int main()
    {
    int location = InsertionSearch(27); //測試代,查27,可以找到
    if(location != -1)
    {
    printf("查找元素順序為: %d\n" ,(location+1));
    }
    else
    {
    printf("沒有查找到");
    }
    return 0;
    }

    運行結果

    運行結果

    4 斐波那契查找

    斐波那契查找與折半查找很相似,他是根據斐波那契序列的特點對有序表進行分割的。他要求開始表中記錄的個數為某個斐波那契數小1,及n=F(k)-1;開始將k值與第F(k-1)位置的記錄進行比較(及mid=low+F(k-1)-1).

    算法思路

  • 相等,mid位置的元素即為所求

  • 大于,low=mid+1,k-=2;

  • 小于,high=mid-1,k-=1。

  • 說明

    low=mid+1說明待查找的元素在[mid+1,high]范圍內,k-=2 說明范圍[mid+1,high]內的元素個數為n-(F(k-1))= Fk-1-F(k-1)=Fk-F(k-1)-1=F(k-2)-1個,所以可以遞歸的應用斐波那契查找。

    代碼

    #include "stdafx.h"
    #include
    #include
    using namespace std;
    const int max_size=20;//斐波那契數組的長度
    /*構造一個斐波那契數組*/
    void Fibonacci(int * F)
    {
    F[0]=0;
    F[1]=1;
    for(int i=2;i F[i]=F[i-1]+F[i-2];
    }
    /*定義斐波那契查找法*/
    int FibonacciSearch(int *a, int n, int key) //a為要查找的數組,n為要查找的數組長度,key為要查找的關鍵字
    {
    int low=0;
    int high=n-1;
    int F[max_size];
    Fibonacci(F);//構造一個斐波那契數組F
    int k=0;
    while(n>F[k]-1)//計算n位于斐波那契數列的位置
    ++k;
    int * temp;//將數組a擴展到F[k]-1的長度
    temp=new int [F[k]-1];
    memcpy(temp,a,n*sizeof(int));
    for(int i=n;i temp[i]=a[n-1];
    while(low<=high)
    {
    int mid=low+F[k-1]-1;
    if(key {
    high=mid-1;
    k-=1;
    }
    else if(key>temp[mid])
    {
    low=mid+1;
    k-=2;
    }
    else
    {
    if(mid return mid; //若相等則說明mid即為查找到的位置
    else
    return n-1; //若mid>=n則說明是擴展的數值,返回n-1
    }
    }
    delete [] temp;
    return 0;
    }
    int main()
    {
    int a[] = {0,1,4,35,47,53,62,78,88,99};
    int key=47;
    int index=FibonacciSearch(a,sizeof(a)/sizeof(int),key);
    if(index == 0)
    {
    cout< }
    else
    {
    cout< }
    return 0;
    }

    運行結果

    47的位置為5

    5 哈希查找

    哈希表

    我們使用一個下標范圍比較大的數組來存儲元素。可以設計一個函數(哈希函數, 也叫做散列函數),使得每個元素的關鍵字都與一個函數值(即數組下標)相對應,于是用這個數組單元來存儲這個元素;也可以簡單的理解為,按照關鍵字為每一個元素"分類",然后將這個元素存儲在相應"類"所對應的地方。但是,不能夠保證每個元素的關鍵字與函數值是一一對應的,因此極有可能出現對于不同的元素,卻計算出了相同的函數值,這樣就產生了"沖突",換句話說,就是把不同的元素分在了相同的"類"之中。后面我們將看到一種解決"沖突"的簡便做法。

    "直接定址"與"解決沖突"是哈希表的兩大特點。

    哈希函數

    規則:通過某種轉換關系,使關鍵字適度的分散到指定大小的的順序結構中,越分散,則以后查找的時間復雜度越小,空間復雜度越高。

    算法思路

    如果所有的鍵都是整數,那么就可以使用一個簡單的無序數組來實現:將鍵作為索引,值即為其對應的值,這樣就可以快速訪問任意鍵的值。這是對于簡單的鍵的情況,我們將其擴展到可以處理更加復雜的類型的鍵。

  • 用給定的哈希函數構造哈希表;
  • 根據選擇的沖突處理方法(常見方法:拉鏈法和線性探測法)解決地址沖突;
  • 在哈希表的基礎上執行哈希查找;
  • 代碼

    #include
    #include
    #define SUCCESS 1
    #define UNSUCCESS 0
    #define OVERFLOW -1
    #define OK 1
    #define ERROR -1
    #define MAXNUM 9999 // 用于初始化哈希表的記錄 key
    typedef int Status;
    typedef int KeyType;
    // 哈希表中的記錄類型
    typedef struct
    {
    KeyType key;
    }RcdType;
    // 哈希表類型
    typedef struct
    {
    RcdType *rcd;
    int size;
    int count;
    int *tag;
    }HashTable;
    // 哈希表每次重建增長后的大小
    int hashsize[] = { 11, 31, 61, 127, 251, 503 };
    int index = 0;
    // 初始哈希表
    Status InitHashTable(HashTable &H, int size)
    {
    int i;
    H.rcd = (RcdType *)malloc(sizeof(RcdType)*size);
    H.tag = (int *)malloc(sizeof(int)*size);
    if (NULL == H.rcd || NULL == H.tag) return OVERFLOW;
    KeyType maxNum = MAXNUM;
    for (i = 0; i < size; i++)
    {
    H.tag[i] = 0;
    H.rcd[i].key = maxNum;
    }
    H.size = size;
    H.count = 0;
    return OK;
    }
    // 哈希函數:除留余數法
    int Hash(KeyType key, int m)
    {
    return (3 * key) % m;
    }
    // 處理哈希沖突:線性探測
    void collision(int &p, int m)
    {
    p = (p + 1) % m;
    }
    // 在哈希表中查詢
    Status SearchHash(HashTable H, KeyType key, int &p, int &c)
    {
    p = Hash(key, H.size);
    int h = p;
    c = 0;
    while ((1 == H.tag[p] && H.rcd[p].key != key) || -1 == H.tag[p])
    {
    collision(p, H.size); c++;
    }
    if (1 == H.tag[p] && key == H.rcd[p].key) return SUCCESS;
    else return UNSUCCESS;
    }
    //打印哈希表
    void printHash(HashTable H)
    {
    int i;
    printf("key : ");
    for (i = 0; i < H.size; i++)
    printf("%3d ", H.rcd[i].key);
    printf("\n");
    printf("tag : ");
    for (i = 0; i < H.size; i++)
    printf("%3d ", H.tag[i]);
    printf("\n\n");
    }
    // 函數聲明:插入哈希表
    Status InsertHash(HashTable &H, KeyType key);
    // 重建哈希表
    Status recreateHash(HashTable &H)
    {
    RcdType *orcd;
    int *otag, osize, i;
    orcd = H.rcd;
    otag = H.tag;
    osize = H.size;
    InitHashTable(H, hashsize[index++]);
    //把所有元素,按照新哈希函數放到新表中
    for (i = 0; i < osize; i++)
    {
    if (1 == otag[i])
    {
    InsertHash(H, orcd[i].key);
    }
    }
    return OK;
    }
    // 插入哈希表
    Status InsertHash(HashTable &H, KeyType key)
    {
    int p, c;
    if (UNSUCCESS == SearchHash(H, key, p, c))
    { //沒有相同key
    if (c*1.0 / H.size < 0.5)
    { //沖突次數未達到上線
    //插入代碼
    H.rcd[p].key = key;
    H.tag[p] = 1;
    H.count++;
    return SUCCESS;
    }
    else recreateHash(H); //重構哈希表
    }
    return UNSUCCESS;
    }
    // 刪除哈希表
    Status DeleteHash(HashTable &H, KeyType key)
    {
    int p, c;
    if (SUCCESS == SearchHash(H, key, p, c))
    {
    //刪除代碼
    H.tag[p] = -1;
    H.count--;
    return SUCCESS;
    }
    else return UNSUCCESS;
    }
    int main()
    {
    printf("-----哈希表-----\n");
    HashTable H;
    int i;
    int size = 11;
    KeyType array[8] = { 22, 41, 53, 46, 30, 13, 12, 67 };
    KeyType key;
    //初始化哈希表
    printf("初始化哈希表\n");
    if (SUCCESS == InitHashTable(H, hashsize[index++])) printf("初始化成功\n");
    //插入哈希表
    printf("插入哈希表\n");
    for (i = 0; i <= 7; i++)
    {
    key = array[i];
    InsertHash(H, key);
    printHash(H);
    }
    //刪除哈希表
    printf("刪除哈希表中key為12的元素\n");
    int p, c;
    if (SUCCESS == DeleteHash(H, 12))
    {
    printf("刪除成功,此時哈希表為:\n");
    printHash(H);
    }
    //查詢哈希表
    printf("查詢哈希表中key為67的元素\n");
    if (SUCCESS == SearchHash(H, 67, p, c)) printf("查詢成功\n");
    //再次插入,測試哈希表的重建
    printf("再次插入,測試哈希表的重建:\n");
    KeyType array1[8] = { 27, 47, 57, 47, 37, 17, 93, 67 };
    for (i = 0; i <= 7; i++)
    {
    key = array1[i];
    InsertHash(H, key);
    printHash(H);
    }
    getchar();
    return 0;
    }

    6 二叉樹查找

    二叉查找樹是先對待查找的數據進行生成樹,確保樹的左分支的值小于右分支的值,然后在就行和每個節點的父節點比較大小,查找最適合的范圍。這個算法的查找效率很高,但是如果使用這種查找方法要首先創建樹。

    算法思路

  • 若b是空樹,則搜索失敗:
  • 若x等于b的根節點的數據域之值,則查找成功:
  • 若x小于b的根節點的數據域之值,則搜索左子樹:
  • 查找右子樹。
  • 代碼

    遞歸和非遞歸

    //非遞歸查找算法
    BSTNode *BST_Search(BiTree T,ElemType key,BSTNode *&p)
    {
    //查找函數返回指向關鍵字值為key的結點指針,不存在則返回NULL
    p=NULL;
    while(T!=NULL&&key!=T->data)
    {
    p=T; //指向被查找結點的雙親
    if(keydata)
    T=T->lchild; //查找左子樹
    else
    T=T->rchild; //查找右子樹
    }
    return T;
    }
    //遞歸算法
    Status Search_BST(BiTree T, int key, BiTree f, BiTree *p)
    {
    //查找BST中是否存在key,f指向T雙親,其初始值為NULL
    //若查找成功,指針p指向數據元素結點,返回true;
    //若失敗,p指向查找路徑上訪問的最后一個結點并返回false
    if(!T)
    {
    *p=f;
    return false;
    }
    else if(key==T->data)
    { //查找成功
    *p=T;
    return true;
    }
    else if(keydata)
    return Search_BST(T->lchild,key,T,p); //遞歸查找左子樹
    else
    return Search_BST(T->rchild,key,T,p); //遞歸查找右子樹
    }

    7 2-3樹

    2-3樹運行每個節點保存1個或者兩個的值。對于普通的2節點(2-node),他保存1個key和左右兩個自己點。對應3節點(3-node),保存兩個Key,2-3查找樹的定義如下:

  • 要么為空,要么:

  • 對于2節點,該節點保存一個key及對應value,以及兩個指向左右節點的節點,左節點也是一個2-3節點,所有的值都比key要小,右節點也是一個2-3節點,所有的值比key要大。

  • 對于3節點,該節點保存兩個key及對應value,以及三個指向左中右的節點。左節點也是一個2-3節點,所有的值均比兩個key中的最小的key還要小;中間節點也是一個2-3節點,中間節點的key值在兩個跟節點key值之間;右節點也是一個2-3節點,節點的所有key值比兩個key中的最大的key還要大。

  • 算法思路:

    要判斷一個鍵是否在樹中,我們先將它和根結點中的鍵比較。如果它和其中的任何一個相等,查找命中。否則我們就根據比較的結果找到指向相應區間的鏈接,并在其指向的子樹中遞歸地繼續查找。如果這是個空鏈接,查找未命中。

    2-3 樹中查找鍵為H的節點2-3 樹中查找鍵為B的節點

    代碼

    two_three *search23(two_three *t, element x)
    {
    while(t)
    {
    if (x < t->data_l)
    {
    t = t->left_child;
    }
    else if (x > t->data_l && x < t->data_r)
    {
    t = t->middle_child;
    }
    else if (x > t->data_r)
    {
    t = t->right_child;
    }
    else
    {
    return t;
    }
    }
    return NULL;
    }

    8 紅黑樹

    2-3查找樹能保證在插入元素之后能保持樹的平衡狀態,最壞情況下即所有的子節點都是2-node,樹的高度為lgn,從而保證了最壞情況下的時間復雜度。但是2-3樹實現起來比較復雜,于是就有了一種簡單實現2-3樹的數據結構,即紅黑樹(Red-Black Tree)。

    理解紅黑樹一句話就夠了:紅黑樹就是用紅鏈接表示3-結點的2-3樹

    現在我們對2-3樹進行改造,改造成一個二叉樹。怎么改造呢?對于2節點,保持不變;對于3節點,我們首先將3節點中左側的元素標記為紅色,然后我們將其改造成圖3的形式;

    再將3節點的位于中間的子節點的父節點設置為父節點中那個紅色的節點,如圖4的所示;最后我們將圖4的形式改為二叉樹的樣子,如圖5所示。圖5是不是很熟悉,沒錯,這就是我們常常提到的大名鼎鼎的紅黑樹了。如下圖所示。

    2-3樹轉紅黑樹

    為什么使用紅黑樹

    • 紅黑樹是一種平衡樹,他復雜的定義和規則都是為了保證樹的平衡性。如果樹不保證他的平衡性就是下圖:很顯然這就變成一個鏈表了。
    • 保證平衡性的最大的目的就是降低樹的高度,因為樹的查找性能取決于樹的高度。所以樹的高度越低搜索的效率越高!
    • 這也是為什么存在二叉樹、搜索二叉樹等,各類樹的目的。

    紅黑樹性質

    • 每個節點要么是黑色,要么是紅色。
    • 根節點是黑色。
    • 每個葉子節點(NIL)是黑色。
    • 每個紅色結點的兩個子結點一定都是黑色。
    • 任意一結點到每個葉子結點的路徑都包含數量相同的黑結點。

    算法思路

    紅黑樹的思想就是對2-3查找樹進行編碼,尤其是對2-3查找樹中的3-nodes節點添加額外的信息。紅黑樹中將節點之間的鏈接分為兩種不同類型,紅色鏈接,他用來鏈接兩個2-nodes節點來表示一個3-nodes節點。黑色鏈接用來鏈接普通的2-3節點。特別的,使用紅色鏈接的兩個2-nodes來表示一個3-nodes節點,并且向左傾斜,即一個2-node是另一個2-node的左子節點。這種做法的好處是查找的時候不用做任何修改,和普通的二叉查找樹相同

    代碼

    #define BLACK 1
    #define RED 0
    #include
    using namespace std;
    class bst
    {
    private:
    struct Node
    {
    int value;
    bool color;
    Node *leftTree, *rightTree, *parent;
    Node() : value(0), color(RED), leftTree(NULL), rightTree(NULL), parent(NULL) { }
    Node* grandparent()
    {
    if (parent == NULL)
    {
    return NULL;
    }
    return parent->parent;
    }
    Node* uncle()
    {
    if (grandparent() == NULL)
    {
    return NULL;
    }
    if (parent == grandparent()->rightTree)
    return grandparent()->leftTree;
    else
    return grandparent()->rightTree;
    }
    Node* sibling()
    {
    if (parent->leftTree == this)
    return parent->rightTree;
    else
    return parent->leftTree;
    }
    };
    void rotate_right(Node *p)
    {
    Node *gp = p->grandparent();
    Node *fa = p->parent;
    Node *y = p->rightTree;
    fa->leftTree = y;
    if (y != NIL)
    y->parent = fa;
    p->rightTree = fa;
    fa->parent = p;
    if (root == fa)
    root = p;
    p->parent = gp;
    if (gp != NULL)
    {
    if (gp->leftTree == fa)
    gp->leftTree = p;
    else
    gp->rightTree = p;
    }
    }
    void rotate_left(Node *p)
    {
    if (p->parent == NULL)
    {
    root = p;
    return;
    }
    Node *gp = p->grandparent();
    Node *fa = p->parent;
    Node *y = p->leftTree;
    fa->rightTree = y;
    if (y != NIL)
    y->parent = fa;
    p->leftTree = fa;
    fa->parent = p;
    if (root == fa)
    root = p;
    p->parent = gp;
    if (gp != NULL)
    {
    if (gp->leftTree == fa)
    gp->leftTree = p;
    else
    gp->rightTree = p;
    }
    }
    void inorder(Node *p)
    {
    if (p == NIL)
    return;
    if (p->leftTree)
    inorder(p->leftTree);
    cout << p->value << " ";
    if (p->rightTree)
    inorder(p->rightTree);
    }
    string outputColor(bool color)
    {
    return color ? "BLACK" : "RED";
    }
    Node* getSmallestChild(Node *p)
    {
    if (p->leftTree == NIL)
    return p;
    return getSmallestChild(p->leftTree);
    }
    bool delete_child(Node *p, int data)
    {
    if (p->value > data)
    {
    if (p->leftTree == NIL)
    {
    return false;
    }
    return delete_child(p->leftTree, data);
    }
    else if (p->value < data)
    {
    if (p->rightTree == NIL)
    {
    return false;
    }
    return delete_child(p->rightTree, data);
    }
    else if (p->value == data)
    {
    if (p->rightTree == NIL)
    {
    delete_one_child(p);
    return true;
    }
    Node *smallest = getSmallestChild(p->rightTree);
    swap(p->value, smallest->value);
    delete_one_child(smallest);
    return true;
    }
    else
    {
    return false;
    }
    }
    void delete_one_child(Node *p)
    {
    Node *child = p->leftTree == NIL ? p->rightTree : p->leftTree;
    if (p->parent == NULL && p->leftTree == NIL && p->rightTree == NIL)
    {
    p = NULL;
    root = p;
    return;
    }
    if (p->parent == NULL)
    {
    delete p;
    child->parent = NULL;
    root = child;
    root->color = BLACK;
    return;
    }
    if (p->parent->leftTree == p)
    {
    p->parent->leftTree = child;
    }
    else
    {
    p->parent->rightTree = child;
    }
    child->parent = p->parent;
    if (p->color == BLACK)
    {
    if (child->color == RED)
    {
    child->color = BLACK;
    }
    else
    delete_case(child);
    }
    delete p;
    }
    void delete_case(Node *p)
    {
    if (p->parent == NULL)
    {
    p->color = BLACK;
    return;
    }
    if (p->sibling()->color == RED)
    {
    p->parent->color = RED;
    p->sibling()->color = BLACK;
    if (p == p->parent->leftTree)
    rotate_left(p->sibling());
    else
    rotate_right(p->sibling());
    }
    if (p->parent->color == BLACK && p->sibling()->color == BLACK
    && p->sibling()->leftTree->color == BLACK && p->sibling()->rightTree->color == BLACK)
    {
    p->sibling()->color = RED;
    delete_case(p->parent);
    }
    else if (p->parent->color == RED && p->sibling()->color == BLACK
    && p->sibling()->leftTree->color == BLACK && p->sibling()->rightTree->color == BLACK)
    {
    p->sibling()->color = RED;
    p->parent->color = BLACK;
    }
    else
    {
    if (p->sibling()->color == BLACK)
    {
    if (p == p->parent->leftTree && p->sibling()->leftTree->color == RED
    && p->sibling()->rightTree->color == BLACK)
    {
    p->sibling()->color = RED;
    p->sibling()->leftTree->color = BLACK;
    rotate_right(p->sibling()->leftTree);
    }
    else if (p == p->parent->rightTree && p->sibling()->leftTree->color == BLACK
    && p->sibling()->rightTree->color == RED)
    {
    p->sibling()->color = RED;
    p->sibling()->rightTree->color = BLACK;
    rotate_left(p->sibling()->rightTree);
    }
    }
    p->sibling()->color = p->parent->color;
    p->parent->color = BLACK;
    if (p == p->parent->leftTree)
    {
    p->sibling()->rightTree->color = BLACK;
    rotate_left(p->sibling());
    }
    else
    {
    p->sibling()->leftTree->color = BLACK;
    rotate_right(p->sibling());
    }
    }
    }
    void insert(Node *p, int data)
    {
    if (p->value >= data)
    {
    if (p->leftTree != NIL)
    insert(p->leftTree, data);
    else
    {
    Node *tmp = new Node();
    tmp->value = data;
    tmp->leftTree = tmp->rightTree = NIL;
    tmp->parent = p;
    p->leftTree = tmp;
    insert_case(tmp);
    }
    }
    else
    {
    if (p->rightTree != NIL)
    insert(p->rightTree, data);
    else
    {
    Node *tmp = new Node();
    tmp->value = data;
    tmp->leftTree = tmp->rightTree = NIL;
    tmp->parent = p;
    p->rightTree = tmp;
    insert_case(tmp);
    }
    }
    }
    void insert_case(Node *p)
    {
    if (p->parent == NULL)
    {
    root = p;
    p->color = BLACK;
    return;
    }
    if (p->parent->color == RED)
    {
    if (p->uncle()->color == RED)
    {
    p->parent->color = p->uncle()->color = BLACK;
    p->grandparent()->color = RED;
    insert_case(p->grandparent());
    }
    else
    {
    if (p->parent->rightTree == p && p->grandparent()->leftTree == p->parent)
    {
    rotate_left(p);
    rotate_right(p);
    p->color = BLACK;
    p->leftTree->color = p->rightTree->color = RED;
    }
    else if (p->parent->leftTree == p && p->grandparent()->rightTree == p->parent)
    {
    rotate_right(p);
    rotate_left(p);
    p->color = BLACK;
    p->leftTree->color = p->rightTree->color = RED;
    }
    else if (p->parent->leftTree == p && p->grandparent()->leftTree == p->parent)
    {
    p->parent->color = BLACK;
    p->grandparent()->color = RED;
    rotate_right(p->parent);
    }
    else if (p->parent->rightTree == p && p->grandparent()->rightTree == p->parent)
    {
    p->parent->color = BLACK;
    p->grandparent()->color = RED;
    rotate_left(p->parent);
    }
    }
    }
    }
    void DeleteTree(Node *p)
    {
    if (!p || p == NIL)
    {
    return;
    }
    DeleteTree(p->leftTree);
    DeleteTree(p->rightTree);
    delete p;
    }
    public:
    bst()
    {
    NIL = new Node();
    NIL->color = BLACK;
    root = NULL;
    }
    ~bst()
    {
    if (root)
    DeleteTree(root);
    delete NIL;
    }
    void inorder()
    {
    if (root == NULL)
    return;
    inorder(root);
    cout << endl;
    }
    void insert(int x)
    {
    if (root == NULL)
    {
    root = new Node();
    root->color = BLACK;
    root->leftTree = root->rightTree = NIL;
    root->value = x;
    }
    else
    {
    insert(root, x);
    }
    }
    bool delete_value(int data)
    {
    return delete_child(root, data);
    }
    private:
    Node *root, *NIL;
    };
    int main()
    {
    cout << "---【紅黑樹】---" << endl;
    // 創建紅黑樹
    bst tree;
    // 插入元素
    tree.insert(2);
    tree.insert(9);
    tree.insert(-10);
    tree.insert(0);
    tree.insert(33);
    tree.insert(-19);
    // 順序打印紅黑樹
    cout << "插入元素后的紅黑樹:" << endl;
    tree.inorder();
    // 刪除元素
    tree.delete_value(2);
    // 順序打印紅黑樹
    cout << "刪除元素 2 后的紅黑樹:" << endl;
    tree.inorder();
    // 析構
    tree.~bst();
    getchar();
    return 0;
    }

    9 B樹/B+樹

    在計算機科學中,B樹(B-tree)是一種樹狀數據結構,它能夠存儲數據、對其進行排序并允許以O(log n)的時間復雜度運行進行查找、順序讀取、插入和刪除的數據結構。B樹,概括來說是一個節點可以擁有多于2個子節點的二叉查找樹。與自平衡二叉查找樹不同,B-樹為系統最優化大塊數據的讀和寫操作。B-tree算法減少定位記錄時所經歷的中間過程,從而加快存取速度。普遍運用在數據庫和文件系統。

    ——維基百科

    B 樹可以看作是對2-3查找樹的一種擴展,即他允許每個節點有M-1個子節點。

    • 定義任意非葉子結點最多只有M個兒子;且M>2;
    • 根結點的兒子數為[2, M];
    • 除根結點以外的非葉子結點的兒子數為[M/2, M];
    • 每個結點存放至少M/2-1(取上整)和至多M-1個關鍵字;(至少2個關鍵字)
    • 非葉子結點的關鍵字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
    • 非葉子結點的指針:P[1], P[2], …, P[M];其中P[1]指向關鍵字小于K[1]的 子樹,P[M]指向關鍵字大于K[M-1]的子樹,其它P[i]指向關鍵字屬于(K[i-1], K[i])的子樹;
    • 所有葉子結點位于同一層;

    如:(M=3)

    算法思路

    從根結點開始,對結點內的關鍵字(有序)序列進行二分查找,如果命中則結束,否則進入查詢關鍵字所屬范圍的兒子結點;重復,直到所對應的兒子指針為空,或已經是葉子結點;

    • 關鍵字集合分布在整顆樹中;
    • 任何一個關鍵字出現且只出現在一個結點中;
    • 搜索有可能在非葉子結點結束;
    • 其搜索性能等價于在關鍵字全集內做一次二分查找;
    • 自動層次控制;

    代碼

    BTNode* BTree_recursive_search(const BTree tree, KeyType key, int* pos)
    {
    int i = 0;
    while (i < tree->keynum && key > tree->key[i])
    {
    ++i;
    }

    // 查找關鍵字
    if (i < tree->keynum && tree->key[i] == key)
    {
    *pos = i;
    return tree;
    }

    // tree 為葉子節點,找不到 key,查找失敗返回
    if (tree->isLeaf)
    {
    return NULL;
    }

    // 節點內查找失敗,但 tree->key[i - 1]< key < tree->key[i],
    // 下一個查找的結點應為 child[i]

    // 從磁盤讀取第 i 個孩子的數據
    disk_read(&tree->child[i]);

    // 遞歸地繼續查找于樹 tree->child[i]
    return BTree_recursive_search(tree->child[i], key, pos);
    }

    B+樹

    B+樹是B樹的變體,也是一種多路搜索樹:

    其定義基本與B-樹同,除了:

    • 非葉子結點的子樹指針與關鍵字個數相同;
    • 非葉子結點的子樹指針P[i],指向關鍵字值屬于[K[i], K[i+1])的子樹, B樹是開區間
    • 為所有葉子結點增加一個鏈指針;
    • 所有關鍵字都在葉子結點出現;

    如:(M=3)

    1

    算法思路

    B+的搜索與B樹也基本相同,區別是B+樹只有達到葉子結點才命中(B樹可以在 非葉子結點命中),其性能也等價于在關鍵字全集做一次二分查找;

    • 所有關鍵字都出現在葉子結點的鏈表中(稠密索引),且鏈表中的關鍵字恰好是有序的;
    • 不可能在非葉子結點命中;
    • 非葉子結點相當于是葉子結點的索引(稀疏索引),葉子結點相當于是存儲(關鍵字)數據的數據層;
    • 更適合文件索引系統;

    參考資料

  • https://www.sohu.com/a/296278527_478315
  • https://www.cnblogs.com/exzlc/p/12203744.htm
  • 這2天,我發現一個超級好玩的社區,有興趣的同學,可以掃碼回復?github?試試!

    長按掃碼,回復 C語言 有驚喜!

    總結

    以上是生活随笔為你收集整理的tail -f 查找关键字_C语言九种查找算法 | 总有一款适合你的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 欧美老熟妇乱xxxxx | 温柔少妇的高潮呻吟 | 91亚洲网 | 精品无码国产污污污在线观看 | 99精品视频免费版的特色功能 | 精品人妻少妇一区二区 | 久久久久久久极品内射 | sese国产| 色哥网 | 久草成人在线视频 | 中文字字幕第183页 欧美特级一级片 | 日日爽天天 | 欧美久久综合 | 久久久久久久久久久国产精品 | 午夜激情影视 | 性少妇mdms丰满hdfilm | 日韩中文字幕第一页 | 亚洲国产成人精品一区二区三区 | 欧美韩日国产 | 高清视频一区二区三区 | 成人激情站 | 久久国产99 | 蜜臀av性久久久久av蜜臀妖精 | 四虎成人在线观看 | 国产精品嫩草影院av蜜臀 | 国产一区在线免费观看 | 操到喷水 | 亚洲无限码 | 日韩精品一区二区三区四区 | 国产精品成人免费精品自在线观看 | 一区二区免费在线播放 | 国产一区二区在线免费 | 色久婷婷 | 自拍偷拍21p | 午夜亚洲精品 | 久久久69 | 亚洲AV无码一区二区三区少妇 | 午夜小视频网站 | 欧美日本高清视频 | 亚洲欧美日韩精品一区 | 精品欧美一区二区三区成人 | 成人做爰的视频 | 精品国产一二三区 | 久久77777 | 日本熟妇色xxxxx日本免费看 | 黄在线免费观看 | 亚洲综合国产精品 | 在线操| 日韩免费在线视频观看 | 三级a视频 | 国产精品theporn88 | 99热99re6国产在线播放 | 久精品视频| 偷拍自拍一区 | 精品网站999 | 老司机深夜福利网站 | 一区二区三区四区精品视频 | 免费人成在线 | 日本美女视频一区 | 国产精品aaa| 朋友人妻少妇精品系列 | 黄色三级网站在线观看 | 黑白配高清国语在线观看 | 免费a v网站| 极品粉嫩小仙女高潮喷水久久 | 中文字幕日韩在线视频 | 国产高清免费在线播放 | 欧美嫩草影院 | 日日夜夜一区二区 | 亚洲尹人 | 日韩性xxxx | 色桃网| 影音先锋丝袜美腿 | 精品国产区 | 看国产一级片 | 国内视频精品 | 欧美激情一区二区 | 日韩欧美在线观看 | 国产成人三级在线 | 亚洲在线观看一区 | 婷婷亚洲综合五月天小说 | 精品一区免费观看 | 日本一区视频在线观看 | 88久久精品无码一区二区毛片 | 亚洲综合射 | yy色综合| 天天视频黄色 | 亚洲天堂视频网站 | 国产一二在线观看 | 中文字幕影片免费在线观看 | 成人做爰100 | 99热这里只有精品2 91免费版黄 | 国产成人av网站 | 美女黄页在线观看 | 五月色丁香 | 亚洲高h| 国产伦精品一区二区三区照片91 | 粉嫩欧美一区二区三区 | 18禁裸乳无遮挡啪啪无码免费 |