數(shù)據(jù)結(jié)構(gòu)-查找

查找

關(guān)鍵詞


  1. 關(guān)鍵字
  2. 主關(guān)鍵字
  3. 次關(guān)鍵字

平均查找長度


定義: 需和給定值比較的關(guān)鍵字的個數(shù)的期望值,成為查找成功時的平均查找長度

對于有n個關(guān)鍵字的表,其平均查找長度如下:
ASL=\sum_{i=1}^nP_iC_i

其中P_i是查找第i個關(guān)鍵字的概率,可知\sum_{i=1}^nP_i=1 (個人理解給定值出現(xiàn)在位置i上的概率)

C_i是在i位置查找到目標(biāo)值時,已經(jīng)比較過的關(guān)鍵字的個數(shù).

靜態(tài)查找表


靜態(tài)查找表的順序存儲結(jié)構(gòu)

typedef struct{
    Elemtype *list;
    int ncount;
}SSTable;

順序查找的實現(xiàn)

從后往前找,零號位置作為哨兵,這樣不用沒找一次比較一次,當(dāng)查找量大于1000的時候,是可以提高一倍效率的.

int search(SSTable &list,Elemtype keyword){
    (list.list)[0]=keyword;
    int i=list.ncount;
    while ((list.list)[i]==keyword) i--;
    return i;
}

性能分析

如果在第一個位置需要查找n次,如果在最后一個位置需要查找1次,于是可以歸納出在第i個位置需要查找<u>n-i+1</u>次

ASL=nP_1+(n-1)P_2+...+(n-i+1)P_i+...+P_n

一般情況下,出現(xiàn)在每個目標(biāo)出現(xiàn)在每個位置的概率時相等的,即P_i=\frac1n

ASL=\frac{1+n}{2}

tip:上述討論是忽略了查找不成功的情況的,一般情況下查找不成功的概率確實小的可以忽略不計.

有序表的查找


折半查找算法(實際上就是二分查找)

int search_bin(SSTable &list,Elemtype key){
    int l=1,r=list.ncount;
    while (l<=r>){
        int mid=(l+r)/2;
        if (key==(list.list)[mid]) return mid;
        else if(key>(list.list)[mid]) l=mid+1;
        else r=mid-1;
    }
    return 0;
}

性能分析

  • 通過判定樹來分析

  • 有n個節(jié)點的樹的最大深度是\log_2n+1

  • 訪問第h層的節(jié)點總共需要訪問h*2^{h-1}個節(jié)點(最壞情況)

二叉樹第h層有2^{h-1}個節(jié)點
h層的二叉樹有2^h-1個節(jié)點
等比數(shù)列公式:
S_n=\frac{a_1(1-q^n)}{1-q}

為了方便計算,假設(shè)一個深度為h的滿二叉樹,此時n=2^h-1(h=\log_2(n+1)),并且目標(biāo)值出現(xiàn)在每個位置的概率是相同的
P_i=\frac1n

可以得到:
\begin{aligned} ASL&=\sum_{i=1}^nP_iC_i\\ &=\frac1n\sum_{j=1}^hj\cdot 2^{j-1}\\ &=\frac{n+1}n\log_2(n+1)-1 \end{aligned}

當(dāng)n比較大的時候(n\geq50)時,可以近似等于
ASL=\log_2(n+1)-1

動態(tài)查找樹表


動態(tài)查找表的特點:表結(jié)構(gòu)本身是在查找過程中動態(tài)生成的,即若存在返回索引,不存在插入

二叉排序樹(BST)


定義:

二叉排序樹或者是一顆空樹,或者是符合以下定義的樹:
(1)若它的左子樹不為空,則左子樹上所有的節(jié)點均小于根節(jié)點上的值
(2)若它的右子樹不為空,則右子樹上所有的節(jié)點均大于根節(jié)點上的值
(3)它的左子樹和右子樹同樣是二叉排序樹

儲存結(jié)構(gòu):(和二叉樹其實是一樣的)

typedef struct BiTNode{
    elemtype data;
    struct BiTNode *lchild,*rchild;
}BiTNODE,*BiTree;

查找算法

BiTree search(BiTree root,elemtype key,BiTree &pre,BiTree &p){
    //p是要傳給外部的參數(shù)
    if (!root) {p=pre;return NULL;} //返回上一個
    if (root->data==key) return root;
    else if(key>root->data) search(root->rchild,key,root);
    else search(root->lchild,key,root,p);
}

插入算法

int add(BiTree &T,elemtype key){
    BiTree temp;
    if (!search(T,key,T,temp)){
        //生成節(jié)點
        BiTree newnode=(BiTree)malloc(sizeof(BiTNode));
        *newnode={key,NULL,NULL};
        if (!temp) T=newnode;
        else{
            if (key>T->data) temp->lchild=newnode;
            else temp->rchild=newnode;
        }
    }
    else return -1;
    return 0;
}

刪除算法

分為三種
(1)被刪除的只有葉子節(jié)點
(2)被刪除的只有左子樹或者右子樹
(3)被刪除的節(jié)點既有左子樹又有右子樹

(1)將雙親節(jié)點的對應(yīng)的指針域改成空

(2)雙親節(jié)點指向被刪除節(jié)點的對應(yīng)的左子樹或者右子樹

(3)可以從左子樹操作也可以從右子樹操作,這里就以左子樹為例.

  1. 找到左子樹里面最大的關(guān)鍵字,替換被刪除節(jié)點
  2. 剛剛用來替換的那個最大的關(guān)鍵字的右子樹一定是空的,用(2)處理以下就可以了
int delete_1(BiTree& t,elemtype key){
    BiTree &pre,temp;
    temp=search(T,key,T,pre);
    if (!temp) return -1;
    else{
        if (!(temp->rchild)) {pre->next=temp->left;free(temp);}
        else if(!(temp->lchild)) {pre->next=temp->right;free(temp);}//這里的pre->next指所對應(yīng)的左子樹或者右子樹
        else{
            BiTree temp2;
            pre=temp;
            temp2=temp->lchild;
            while (temp2->rchild){pre=temp2; temp2=temp2->rchild;}
            temp->data=temp2->data;
            pre->next=temp2->right;
            free(temp2);
        }
    }
}

tip:這里的代碼可能有問題,重點看一下思路吧

conclude: 對于經(jīng)常需要刪除和添加的有序表,使用二叉排序樹是比較合適的

查找性能分析

對于不同的插入順序,構(gòu)造出來的二叉排序樹是不一樣的,于是查找的復(fù)雜度也是不一樣的,于是這里直接給出計算后的平均值

ASL=2\frac{n+1}{n}\log{n}+C

二叉平衡樹


定義: 平衡二叉樹又稱AVL樹.它或者是一棵空樹,或者是一棵具有如下性質(zhì)的樹:
(1) 它的左子樹和右子樹都是平衡二叉樹
(2) 他的左右子樹深度之差的絕對值不超過1

平衡因子

左子樹的深度與右子樹深度的差值(注意先后順序)

特點

平衡因子的絕對值不大于1

構(gòu)造-平衡旋轉(zhuǎn)技術(shù)

平衡旋轉(zhuǎn)技只針對最小不平衡子樹

平均查找長度在log級別上

4種平衡旋轉(zhuǎn)

  1. LL型,右旋一次,被折下去的那個節(jié)點的左子樹會空出來,由定義可以知道,被折下去的部分一定是大于左邊部分的,于是空出來的位置可以接上折上去的節(jié)點的右子樹.

  2. RR型,左旋一次,其余原理同LL型是一致的.

  3. LR型

  4. RL型

tip:怎么插入的這個節(jié)點其實和如何旋轉(zhuǎn)對應(yīng)上了

B-樹


(待續(xù))

哈希表


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末玫鸟,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子犀勒,更是在濱河造成了極大的恐慌屎飘,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贾费,死亡現(xiàn)場離奇詭異钦购,居然都是意外死亡,警方通過查閱死者的電腦和手機褂萧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門押桃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人导犹,你說我怎么就攤上這事唱凯。” “怎么了锡足?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵波丰,是天一觀的道長。 經(jīng)常有香客問我舶得,道長掰烟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任沐批,我火速辦了婚禮纫骑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘九孩。我一直安慰自己先馆,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布躺彬。 她就那樣靜靜地躺著煤墙,像睡著了一般梅惯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上仿野,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天铣减,我揣著相機與錄音,去河邊找鬼脚作。 笑死葫哗,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的球涛。 我是一名探鬼主播劣针,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼亿扁!你這毒婦竟也來了捺典?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤魏烫,失蹤者是張志新(化名)和其女友劉穎辣苏,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哄褒,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年煌张,在試婚紗的時候發(fā)現(xiàn)自己被綠了呐赡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡骏融,死狀恐怖链嘀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情档玻,我是刑警寧澤怀泊,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站误趴,受9級特大地震影響霹琼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜凉当,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一枣申、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧看杭,春花似錦忠藤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽尖阔。三九已至,卻和暖如春榨咐,著一層夾襖步出監(jiān)牢的瞬間介却,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工祭芦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留筷笨,地道東北人。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓龟劲,卻偏偏與公主長得像胃夏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子昌跌,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容