1. 程式人生 > 其它 >資料結構——有序向量的查詢與改進

資料結構——有序向量的查詢與改進

有序向量的查詢

查詢

  • 介面:tempalte static Rank search(T* a,T const& e, Rank lo, Rank hi)
  • 語義規定:在有序向量的區間[lo, hi)內,確定不大於e的最後一個節點的秩
  • 複雜度:若採用最樸素的二分策略,那麼每次都將問題規模縮小一半左右,這樣經過至多\(log_2(hi-lo)\)次迭代,複雜度不超過\(O(logn)\),而改進基本上是線性因子。
  • 查詢長度:查詢演算法執行元素大小比較操作的次數

二分查詢

語義規定:在有序向量的區間[lo, hi)內,返回e的秩,若有多個相同值則返回最大的秩,若查詢失敗則返回-1

原理:每次取lo與hi的終點,不停調整區間,經過至多兩次比較可以完成一次迭代。
直到最後lo>=hi時(其實就是lo=hi),此時的區間寬度為0,表示查詢失敗了。

// 二分查詢演算法(版本A):在有序向量的區間[lo, hi)內查詢元素e,0 <= lo <= hi <= _size
template <typename T> static Rank binSearch ( T* S, T const& e, Rank lo, Rank hi ) {
   while ( lo < hi ) { //每步迭代可能要做兩次比較判斷,有三個分支
      Rank mi = ( lo + hi ) >> 1; //以中點為軸點(區間寬度的折半,等效於寬度之數值表示的右移)
      if      ( e < S[mi] ) hi = mi; //深入前半段[lo, mi)繼續查詢
      else if ( S[mi] < e ) lo = mi + 1; //深入後半段(mi, hi)繼續查詢
      else                  return mi; //在mi處命中
   } //成功查詢可以提前終止
   return -1; //查詢失敗
} //有多個命中元素時,不能保證返回秩最大者;查詢失敗時,簡單地返回-1,而不能指示失敗的位置

查詢長度分析:
為了評定各個查詢的細微差距,我們考察查詢長度,同樣有最好最壞和平均。
這裡我們依舊考察平均查詢長度:\(C_{average}(k)\)
設在長度為\(n=2^k-1\)的有序向量中進行查詢
1、成功查詢長度

遞推基:
\(C_{average}(k)=C(1)=2\)
遞推分析:對於成功查詢,總共有三種情況
1.經過1次比較,問題轉化為2^{k-1}-1的新問題;
2.經過2次比較,問題轉化為2^{k-1}-1的新問題;
3.經過2次比較,在mid處命中,查詢成功.
那麼則有遞推公式

\[C(k) = [C(k-1)+(2^{k-1}-1)] + 2 +[C(k-1)+2*(2^{k-1}-1)]=2*C(k-1)+3*2^{k+1}-1 \]

\[F(k)=C(k)-3k*2^{k-1}-1 \]

則有

\[F(1)=2;F(k)=2F(k-1)=2^2F(k-2)=\dots=2^{k-1}F(1)=-2^k \]

於是

\[C(k) = F(k)+3k*2^{k-1}+1=(\frac{3}{2}k-1)*(2^k-1)+ \frac{3}{2}k \]

進而得到

\[C_{average}=\frac{C(k)}{2^k-1}=\frac{3}{2}k-1+\frac{3}{2}k*\frac{1}{2^k-1}=\frac{3}{2}k-1+O(\varepsilon) \]

n趨於無窮時忽略末尾收斂的無窮小量平均查詢長度為:

\[O(1.5k)=O(1.5\cdot log_{2}n) \]

Fibonacci查詢

二分查詢·改

// 二分查詢演算法(版本B):在有序向量的區間[lo, hi)內查詢元素e,0 <= lo < hi <= _size
template <typename T> static Rank binSearch ( T* S, T const& e, Rank lo, Rank hi ) {
   while ( 1 < hi - lo ) { //每步迭代僅需做一次比較判斷,有兩個分支;成功查詢不能提前終止
      Rank mi = ( lo + hi ) >> 1; //以中點為軸點(區間寬度的折半,等效於寬度之數值表示的右移)
      ( e < S[mi] ) ? hi = mi : lo = mi; //經比較後確定深入[lo, mi)或[mi, hi)
   } //出口時hi = lo + 1,查詢區間僅含一個元素A[lo]
   return e < S[lo] ? lo - 1 : lo; //返回位置,總是不超過e的最大者
} //有多個命中元素時,返回秩最大者;查詢失敗時,簡單地返回-1,而不能指示失敗的位置

二分查詢·改二

template <typename T> static Rank binSearch ( T* S, T const& e, Rank lo, Rank hi ) {
   while ( lo < hi ) { //每步迭代僅需做一次比較判斷,有兩個分支
      Rank mi = ( lo + hi ) >> 1; //以中點為軸點(區間寬度的折半,等效於寬度之數值表示的右移)
      ( e < S[mi] ) ? hi = mi : lo = mi + 1; //經比較後確定深入[lo, mi)或(mi, hi)
   } //成功查詢不能提前終止
   return lo - 1; //迴圈結束時,lo為大於e的元素的最小秩,故lo - 1即不大於e的元素的最大秩
} //有多個命中元素時,返回秩最大者;查詢失敗時,能夠返回失敗的位置