算法导论的摊还分析章中的一道思考题,挺有意思的,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;
}