动态二分搜索器

算法导论的摊还分析章中的一道思考题,挺有意思的,2天以来用空闲时间写了下,debug亲测可运行。

//DynBinSearcher.h

#ifndef DYNBINSEARCHER_
#define DYNBINSEARCHER_

template <class T>
int binary_search(T key, T *arr, const int size){
   int i = 0, j = size;
   int mid = 0;
   while (i < j){
      mid = (i + j) / 2;
      if (key < arr[mid]){
         j = mid;
      }
      else{
         if (key > arr[mid]){
            i = mid + 1;
         }
         else{
            return mid;
         }
      }
   }
   return -1;
}

struct Pair{
   Pair(int n_1, int n_2){
      i = n_1;
      j = n_2;
   }
   int i;
   int j;
};

template <class T>
/* Dynamic binary seacher
* Brief: an improved version of binary search,
* elements are partitioned into ⌈lg(n+1)⌉
* sorted subarrays with size of 1, 2, 4, ..., 2^⌈lg(n+1)⌉,
* Although each individual array is sorted, elements in
* different arrays bear no particular relationship to each
* other.
* search:   scan every subarrays from left to right, if
* element is possibly in this subarray, then search it.
* deletion: search the position of element, then take one
* element from another subarray to replace it.
* efficiency:
* search: (worst case)lg(n)*lg(n)
* insert: (worst case)O(n) (armotized cost)O(lg(n))
* erase: (worst case)O(n) (armotized cost)O(lg(n))
*/
class DynBinSearcher{
   template <class T>
   friend int binary_search(T, T *, const int);

public:
   //IN ASSERTION: size != 0
   DynBinSearcher(unsigned int size){
      begin = 0;
      //calculation of total bits needed
      int i = 0;
      while ((size >>= 1) | 0){
         i++;
      }
      num = i + 1;
      arrays = new T*[num];
      //subarrays' space allocation
      for (; i >= 0; i--){
         arrays[i] = new int[1 << i];
      }
      //allocation for count
      begin = 0;
      full_bit = -1;
      extra_bit = -1;
   }

   ~DynBinSearcher(){
      destroyArrays();
   }

   Pair search(const T &);
   //bool search(const T &)const;
   void insert(const T &);
   bool erase(const T &);
#ifdef TEST
   void output();
#endif

private:
   //helper function to destroy current arrays
   void destroyArrays(){
      for (int i = 0; i < num; i++){
         delete[]arrays[i];
      }
      delete[]arrays;
   }
   //for code simplicity, return 0 when full_bit == -1,
   //2^full_bit otherwise.
   inline int full()
   {
      return (full_bit == -1) ? 0 : 1 << full_bit;
   }
   //return the size of a subarray.
   inline int size(int index)
   {
      if (index <= full_bit){
         return 1 << index;
      }
      if (index < begin){
         return full() + extra_bit + 1;
      }
      return full() + extra_bit;
   }
   //span space as twice bigger
   void grow();

   T **arrays;
   int num;
   //begin: current subarray to insert
   int begin;
   //extra_bit: extra bits in subarray ayyays[begin].
   int extra_bit;
   //full_bit: the rightest full subarray.
   int full_bit;
};

template <class T>
Pair DynBinSearcher<T>::search(const T &x){
   int i = 0, j = 0;
   while (i < num){
      if (arrays[i][0] < x &&
          x < arrays[i][size(i) - 1] &&
          -1 != (j = binary_search(x, arrays[i], size(i)))
          ){
         return Pair(i, j);
      }
      if (arrays[i][0] == x){
         return Pair(i, 0);
      }
      if (arrays[i][size(i) - 1] == x){
         return Pair(i, size(i) - 1);
      }
      i++;
   }
   //not found, set i = j = -1
   return Pair(-1, -1);
}

template <class T>
void DynBinSearcher<T>::insert(const T &x){
   int i = 0;
   int size = full() + extra_bit;
   for (; i < size; i++){
      if (arrays[begin][i] > x){
         break;
      }
   }
   for (int j = size; j > i; j--){
      arrays[begin][j] = arrays[begin][j - 1];
   }
   arrays[begin][i] = x;

   //update parameters
   if (++begin == num){
      if (++extra_bit == full()){
         extra_bit = 0;
         if (++full_bit == num - 1){
            //no free space now...
            //allocate twice memory 
            grow();
         }
      }
      begin = full_bit + 1;
   }
}

template <class T>
bool DynBinSearcher<T>::erase(const T &x){
   Pair pos(0, 0);
   pos = search(x);
   int i = pos.i, j = pos.j;

   if (i == -1){
      //x not found
      return false;
   }

   if (--begin == full_bit){
      if (extra_bit == 0){
         full_bit--;
         extra_bit = full() - 1;
      }
      else{
         extra_bit--;
      }
      begin = num - 1;
   }

   int filler = arrays[begin][size(begin)];
   while (0 < j && filler <= arrays[i][j - 1]){
      arrays[i][j] = arrays[i][j - 1];
      --j;
   }
   while (j < size(i) - 1 && filler > arrays[i][j + 1]){
      arrays[i][j] = arrays[i][j + 1];
      ++j;
   }
   arrays[i][j] = filler;

   return true;
}

template <class T>
void DynBinSearcher<T>::grow(){
   //calculate new size
   int ol_size = num;
   int k = 1;
   while ((ol_size >>= 1) || 0) ++k;
   int more = (1 << k) - k - 1;
   k = num - k;
   //allocation
   T **new_array = new T *[num + more];
   for (int s = 0; s < num + more; s++){
      new_array[s] = new T[1 << s];
   }
   //initialization
   int j = 0;
   for (; j <= k; j++){
      for (int p = 0; p < size(j); p++){
         new_array[j][p] = arrays[j][p];
      }
   }
   for (; j < num; j++){
      for (int p = 0; p < (1 << k); p++){
         new_array[j][p] = arrays[j][p];
      }
   }
   int i = k + 1;
   for (; i < num; i++){
      int r = 1 << k;
      for (int n = 0; n < (1 << (i - k)) - 1; n++, j++){
         for (int m = 0; m < (1 << k); m++, r++){
            new_array[j][m] = arrays[i][r];
         }
      }
   }

   //reset arrays
   destroyArrays();
   arrays = new_array;

   //update parameters
   num += more;
   begin = k + 1;
   extra_bit = 0;
   full_bit = k;
}

#ifdef TEST
template <class T>
void DynBinSearcher<T>::output(){
   for (int i = 0; i < num; i++){
      for (int j = 0; j < size(i); j++){
         cout << setw(4) << arrays[i][j];
         if ((1 + j) % 16 == 0){
            cout << endl;
         }
      }
      cout << "\n--------------------------------" << i 
         << "--------------------------------\n";
   }
   cout << endl;
}
#endif

#endif
//DynBinSearcher_test.cpp
#include <iostream>
#include <iomanip>
#include <ctime>
using namespace std;

#define TEST 1
#define DATA_SIZE 400
#include "DynBinSearcher.h"
#include "ArrayQueue.h"

int main(){
   srand(time(0));

   DynBinSearcher<int> dbs(10);
   ArrayQueue<int> recorder(DATA_SIZE);
   //insertion test
   for (int i = 0; i < DATA_SIZE; i++){
      if (i == 50){
         dbs.insert(19);
         recorder.enqueue(19);
         continue;
      }
      int x = rand() % 100 + 1;
      recorder.enqueue(x);
      dbs.insert(x);
     /* cout << "insert(" << x << ")" << endl;
      dbs.output();*/
   }
   dbs.output();

   //search test
   Pair p_19 = dbs.search(19);
   cout << "search 19: " 
      << "(" << p_19.i << "," << p_19.j << ")" << endl;

   //deletion test
   for (int i = 0; i < DATA_SIZE; i++){
      int x = recorder.front();
      if (!dbs.erase(x)) 
         cout << "ERROR: " << x << "NOT FOUND\n";
      recorder.dequeue();
   }
   cout << "clear." << endl;
   dbs.output();

   return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值