目錄算法
\[ASL=\sum_{i=1}^n P_iC_i\]數據庫
其中P是查找低i個數據元素的機率,通常認爲機率相同即1/n。C是找到第i個數據元素所須要的比較次數。數據結構
對錶進行之間的掃描app
int Search(int a[], int len, int k){ for(int i=0;i<len-1;i++) if(a[i]==k) return i; return -1; }
\[ ASL_{成功}=\sum P_i(n-i+1)=\frac{n+1}{2} \]函數
\[ ASL_{失敗}=n+1 \]性能
int Search(int a[], int len, int k){ int low=0, high=len-1, mid; while(low<=high){ mid=(low+high)/2; if(a[mid]==k) return mid; else if(a[mid]>k) high=mid-1; else low=mid+1; } return -1; }
查找的過程相似於二叉查找樹,因此能夠引入二叉樹來描述,稱爲斷定樹。
查找次數不會超過樹的深度。spa
\[ ASL= \frac { 1 } { n } \sum _ { i = 1 } ^ { n } l _ { i } = \frac { 1 } { n } \left( 1 \times 1 + 2 \times 2 + \cdots + h \times 2 ^ { h - 1 } \right) = \frac { n + 1 } { n } \log _ { 2 } ( n + 1 ) - 1 \approx \log _ { 2 } ( n + 1 )-1 \]3d
分塊查找將查找表分爲若干個塊,爲每一個區塊創建一個索引,肯定下標的上下界後使用順序查找。查找索引使用二分法。
指針
若索引查找和塊內查找的ASL爲Li和Ls,那麼分塊查找的ASL:code
\[ ASL=L_i+L_s \]
二叉查找樹又稱二叉排序樹(BST)。是一種特殊性質的二叉樹,其中左子樹的結點的關鍵字都小於根結點,右子樹大於根結點。
typedef struct BNode{ int key; struct BNode *lchild; struct BNode *rchild; }BNode, *BTree;
BNode* BSTSearch(BTree T, int key){ if(T==NULL) return NULL; if(T->key==key) return T; if(key<T->key) return BSTSearch(T->lchild, key); else return BSTSearch(T->rchild, key); }
int BSTInsert(BTree& T, int key){ if(T==NULL){ T=(BTree)malloc(sizeof(BNode)); T->key=key; T->lchild=T->rchild=NULL; return 1; } else if(key=T->key) return 0; else if(k<T->key) return BSTInsert(T->lchild, key); else return BSTInsert(T->rchild, key); }
void CreateBST(BTree &T, int[] a, int len){ T=NULL; int i=0; while(i<n){ BSTInsert(T, a[i]); i++; } }
刪除這裏通常不會考代碼,知道有那麼三種狀況便可。
第三種狀況可能有點難理解,結合圖來理解一下。
二叉搜索的搜索時間取決於樹的長度,因而可能會出現一種極端的狀況。
二叉平衡樹(AVL)是一種刪除和插入結點時任意結點的左右子樹相差不會超過1的二叉搜索樹。這樣能夠加強搜索的性能。
定義平衡因子:左子樹和右子樹的高度差。
圖中結點的值爲其平衡因子:
保證平衡的想法就是:當咱們插入或者刪除結點的時候,先檢查插入路徑上的結點的平衡因子的絕對值是否大於1。若是是,找到離插入點最近的一個絕對值大於1的結點,對其進行調整。
即咱們調整的對象都是最小的不平衡樹。
對於平衡操做這裏分了四種狀況討論:
狀況:A的左孩(L)的左子樹(L)插入新結點。
操做:B右旋(R),BR替換AL。
狀況:A的右孩(R)的右子樹(R)插入新結點。
操做:B左旋(L),BL替換AR。
狀況:A的左孩(L)的右子樹(R)。
操做:將A的左孩子的右子樹的結點C(BR)先左後右旋轉到A。(注意這裏的操做對於的都是上面的操做的複合)。
狀況:A的右孩(R)的左子樹(L)。
操做:將A的右孩的左子樹的結點C(BL)先右後左旋轉A
記住全部調整都是爲了給插入結點空出位置來的,按照這個思路記憶會方便不少。
B樹能夠視做爲二叉平衡樹的一種拓展,也稱多路平衡搜索樹。
知足以下特性:(m做爲B樹的階數,通常≥3)
B 樹的查找是跟二叉樹相似的多路查找。
分爲兩步:
因爲 B 樹通常用於數據庫中,即在根據指針在磁盤中找到結點並讀到內存中,再在內存中對有序表進行二分搜索,找不到就根據指針讀下一個結點,一直找到葉結點爲止。
分裂
這裏分刪除的節點是否在終端節點來討論。
刪除的關鍵在於要使得結點的關鍵字數量≥[m/2]-1。
在終端節點上,分三類狀況:
不在終端節點上,這種狀況要轉化爲上面那種狀況來討論:
即咱們將要刪除的非終端節點與終端節點進行交換,再按終端節點的方式進行刪除。
這裏引入一個相鄰關鍵字的概念。對於不在終端節點上的結點來講,其相鄰關鍵字爲左子樹中值最大的關鍵字和右子樹中最小的關鍵字。
找相鄰關鍵字的方法與找二叉排序樹中前驅和後繼的方法相似。
沿着左子樹右指針或者右子樹左指針一直到終端結點就是相鄰關鍵字了。
一棵m階的 B+樹知足:
B+樹與 B 樹的主要區別在於:
即理想狀況下,散列表的查找複雜度應該爲 O(1)。
散列函數的構造要求:
下面是一些經常使用的散列函數:
通常來講,散列函數不可能避免衝突,因此會對 key 進行再散列,用Hi表示第 i 次探測到的散列地址。
開放定址法即若是發生了衝突,能夠經過一個遞推公式一直遞推去找空閒的空間。
遞推公式爲:
\[H_i=(H(key)+d_i)\%m\]
其中 m 表示散列表表長,di爲增量的一個序列。
在開放定值法的狀況下, 物理表中的元素不能隨意刪除,由於刪除元素會截斷其餘具備相同散列地址的元素的查找地址。暫時只能在邏輯上刪除。
爲了不同義詞衝突,能夠把全部同義詞存儲在一個線性表中。
若是關鍵詞序列爲{19,14,23,01,68,20,84,27,55,11,10,79}
散列函數爲 H(key)=key%13。
拉鍊法圖示爲:
散列表的性能通常取決於三個因素,散列函數,處理衝突,和裝填因子。
裝填因子 α = 表中記錄 n / 散列長度 m。
串的模式匹配即求模式串在主串中的位置。
int Index(String S,String T){ for(int i=0;i<T.len;i++) for(int j=0;j<S.len;j++){ if(S[j]=T[i]) if(j==S.len-1) return TRUE; else break; } return FALSE; }
複雜度爲:O(n*m),n 和 m 分別爲主串和模式串的長度。
void GetNext(String S, int next[]){ int i=1,j=0; next[1]=0; while(i<S.len){ if(j==0||S.ch[i]==S.ch[j]){ i++;j++; next[i]=j; } else j=next[j]; } } int KMP(String S, String T, int next[]) { int i=1;j=1; while(i<T.len && j<=S.len){ if(j==0||T.ch[i]==S.ch[j]){ i++; j++; } else{ j=next[j]; } if(j>S.len) return i-S.len; else return 0; } }