【C/C++】查找(一):靜態查找表


  {靜態查找表 + 動態查找表}
    所謂動態,就是,找的時候沒有則添加,或者能刪除

  關鍵字:primary key:用來表示查找表中的一條記錄
    {主關鍵字 + 次關鍵字}
    主關鍵字是唯一的,用來唯一的標識查找表中的一條記錄

 


(一)靜態查找表

一、順序表
  類似於數組,順序存儲,在表中有位置,查找即給定關鍵字,遍歷這個表,找到其位置或給出整條記錄;
  可以設置“哨兵” ,即標記0號元素就是要找的關鍵字:這樣可以減去每次判斷是否查找結束的麻煩,平均時間幾乎減少一半

  優化:
    若訪問頻度不同,則設置頻度域,根據需要調整位置,如每次將剛剛訪問過得節點放在最后。

intsearch_Seq(SSTable ST,KeyType key){ //在順序表ST中 找key 
    ST.elem[0].key = key; for(int i = ST.Length;!EQ(ST.elem[i].key,key),--i); return i; //找不到返回0 
}


算法復雜度分析:

  最壞條件下:O(n)
  平均:
    (1+2+...+n) / n (等概率被查找到的情況下)
    O((1+n)/2)
  若考慮查找不成功,則查找不成功的情況都是查找n+1次。
  那么:
    O((n+1)*3/4)

  def:
  平均查找長度:為確定就在查找表中的位置,需和給定值進行比較的關鍵字的個數的期望值稱為查找成功時的平均查找長度
  即:
    ASL = 求和(pi * Ci)
    Ci為第i元素查找的步數

二、 有序表的查找
  主要講三種,第一是經典的二分 直接貼代碼

int Search_Bin(SSTable ST,KeyType key) { int low = 1; int high = ST.Length; int mid; while(low<=high){ mid = (low+high)/2; if(EQ(key,ST.elem[mid].key)){ return min; }else if(LT(key,ST.elem[mid].key)){ high = mid - 1; }else{ low = mid + 1; } } return 0; }


二分法的復雜度分析:(面試等常問的)
  將查找過程構建成一棵樹,樹的節點是每次訪問的mid,這叫判定樹
  由於樹的深度h,定點數n = 2^h-1
  同一深度上的節點被查找需要查找走的步數就是深度h
  那么:
  平均查找,在等概率下:
    ASL = (求和i從1到最高層h(i*2^(i-1)))/n
  因為,第i層上要比較i次,第i層有2^(i-1)個結點

  當每個節點被查找到的概率不同時,二分查找可能並不是最優的,最優的是:
  PH = 求和(p*c)的查找,即判定樹的帶權內路徑長度之和最小
  但這樣做很復雜,可以以一種求折中的方法:求次優查找樹

  思想:
    求一個結點,它的左右兩邊的點被查找到的概率最大可能性的相等, 則該點設置為mid
    遞歸,查找左子樹、右子樹

  實現:
    為了方便,設置權值之和SWi:即從開始到第i點的權值之和
    則每次查找一個點,只要計算該點右邊之和減去左邊的(各自區間內) ,取最小點

  細節注意:
    這並沒有考察單個關鍵字的權值,有的時候,被選作根(mid)的關鍵字的權值比與他相鄰的關鍵字的權值小
    此時應做調整

  復雜度分析:
    構造一棵次優查找樹,復雜度是:
       O(nlogn)
  算法實現:

    //建立樹T,根節點T,使用:R是查找表,sw是其權值,low-high是當前區間
    int i = low; float min = fabs(R[high] - R[low]); float dw = sw[high] + sw[low-1]; for(int j = low+1;j<=high;j++){ if(fabs(dw - sw[j] - sw[j-1]) < min){ min = dw - sw[j] - sw[j-1]; i = j; } } //i作為mid 
    T = (BiTree)malloc(sizeof(BiTNode)); T->data = R[i]; if(i == low){ T->lchild = NULL; }else{ SecondOptimal(T->lchild,R,sw,low,i-1); } if(i == high){ T->rchild = NULL; }else{ SecondOptimal(T->rchild,R,sw,i+1,high); } }

綜合如下:

typedef BiTree SOSTree; Status CreateSOSTree(SOSTree &T,SSTable ST){ if(ST.Length == 0){ T = NULL; } else{ findSW(sw,ST);//建立sw數組,權值和
        SecondOptimal(T,ST.elem,sw,1,ST.Length); } return OK; }

 

靜態查找還有:斐波那契、插值查找

  斐波那契:
    Fn = Fn-1 + Fn-2;
    F1 = 1;
    F0 = 0;
  斐波那契查找就是:
    假設表長我某個斐波那契值-1,即n = Fu-1;
    則在F(u-1)與key比較
    找不到就:
      if key<F(u-1).key:
        在1..F(u-1)中找
      else:
        在F(u-1)+1 ... F(u) 中找
  分析:
    平均復雜度比二分好,但最壞情況下的一次查找不如二分


  而插值查找:
    每次比較的i(相當於二分中的mid),i是有公式算的。
    平均性能比二分好。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM