本章题目是搜索。研究的题目是这样的:在没有其他相关数据的情况下,如何存储一组数组?这个问题虽然很小,但却能引发在数据结构实现中出现的许多关键问题。
除了直接调用C++的模板库,作者提出了自己实现接口的四种解决方案。库的作用。C++标准模板库提供了一个实现起来很容易,并且维护和扩展也比较简单的通用解决方案。当遇到设计数据结构的问题时,我们的第一反应是寻求解决问题的通用工具。但本章中,专用的代码可以充分利用特定问题的性质,大大提高运行速度。
我们希望存储的整数是第十二章中产生的随机数,并按顺序存储。
方案一:
线性结构实现。我们知道线性结构有两种实现方式:数组和链表。数组的优点是查询比较方便,缺点是插入和删除需要大量的数据移动;链表恰好相反。
方案二:
二分搜索树实现。大量节省了插入时间。
方案三:
位图实现。位图结构可以节省大量的空间。
方案四:
“数组箱”实现。“数组箱”结合了链表和位向量的优点,有点儿类似散列。
下面是这四种方案实现的代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
using namespace std;
#define MAX 200
#define MAXAMOUNT 50
#define RAND_MAX 10000
#define BITSPERWORD 32
#define MASK 0x1F
#define SHIFT 5
int bigrand()
{
return rand()*RAND_MAX+rand();
}
int randint(int l, int u)
{
return l+rand()%(u-l+1);
}
//方法一:线性表之数组实现
class IntegerSetArray
{
public:
IntegerSetArray()
{
n = 0;
x = new int[1+MAXAMOUNT];
x[0] = MAX;
}
void insert(int t)
{
int i, j;
for(i=0; x[i]<t;i++)
;
if(x[i] == t)
return;
for(j=n; j>=i; j--)
x[j+1] = x[j];
x[i] = t;
this->n++;
}
int size()
{
return this->n;
}
void report()
{
int i;
for(i=0; i<n; i++){
printf("%d ", x[i]);
}
printf("\n");
}
void genknuth(int m, int n)
{
int i;
for(i=0; i<n; i++){
if(bigrand() % (n-i) < m){
insert(i);
m--;
}
}
}
private:
int n;
int *x;
};
//方法一:线性表之链表实现
class IntegerSetList
{
private:
int n;
struct node{
int val;
node *next;
node(int v, node *p){
val = v;
this->next = p;
}
};
node *head;
node *sentinel;
public:
IntegerSetList()
{
this->sentinel = this->head = new node(MAX, NULL);
n = 0;
}
void insert(int t)
{
this->head = rinsert(t, head);
}
node *rinsert(int t, node *p)
{
if(p->val < t)
p->next = rinsert(t, p->next);
else if(p->val > t){
p = new node(t, p);
n++;
}
return p;
}
void report()
{
node *p;
for(p = head; p!=sentinel; p=p->next){
printf("%d ", p->val);
}
printf("\n");
}
void genknuth(int m, int n)
{
int i;
for(i=0; i<n; i++){
if(bigrand() % (n-i) < m){
insert(i);
m--;
}
}
}
};
//方法二:二分搜索树实现
class IntegerBST
{
private:
int n;
struct node{
int val;
node *left, *right;
node(int v){
val = v;
left = right = NULL;
};
};
node *root;
public:
IntegerBST()
{
this->root = NULL;
n = 0;
}
void insert(int t){
root = rinsert(root, t);
}
node *rinsert(node *p, int t)
{
if(p == NULL){
p = new node(t);
n++;
}
if(p->val < t)
p->right = rinsert(p->right, t);
else if(p->val > t)
p->left = rinsert(p->left, t);
return p;
}
void report()
{
traverse(this->root);
printf("\n");
}
void traverse(node *p)
{
if(p == NULL)
return;
traverse(p->left);
printf("%d ", p->val);
traverse(p->right);
}
void genknuth(int m, int n)
{
int i;
for(i=0; i<n; i++){
if(bigrand() % (n-i) < m){
insert(i);
m--;
}
}
}
};
//方法三:位图向量实现
class IntegerBitVector
{
private:
int n;
int *x;
public:
IntegerBitVector()
{
x = new int[1+MAX>>5];
for(int i=0; i<MAX; i++){
clear(i);
}
n = 0;
}
void insert(int t)
{
if(test(t))
return;
set(t);
n++;
}
void report()
{
int i = 0;
for(i=0; i<MAXAMOUNT; i++){
if(test(i)){
printf("%d ", i);
}
}
}
void set(int i)
{
x[i>>SHIFT] |= (1<<(i & MASK));
}
void clear(int i)
{
x[i>>SHIFT] &= ~(1<<(i & MASK));
}
int test(int i)
{
return x[i>>SHIFT] & (1<<(i & MASK));
}
void genknuth(int m, int n)
{
int i;
for(i=0; i<n; i++){
if(bigrand() % (n-i) < m){
insert(i);
m--;
}
}
}
};
//方法四:结合链表和位向量的优点的箱数组实现
class IntegerSetBins
{
private:
int n, bins;
struct node{
int val;
node *next;
node(int v, node *p){
val = v;
next = p;
};
};
node **bin, *sentinel;
public:
IntegerSetBins()
{
bins = MAXAMOUNT;
n = 0;
bin = new node*[bins];
sentinel = new node(MAX, NULL);
for(int i=0; i<bins; i++){
bin[i] = sentinel;
}
}
void insert(int t)
{
int i;
i = t/(1+MAX/bins);
bin[i] = rinsert(t, bin[i]);
}
node *rinsert(int t, node *p)
{
if(p->val < t)
p->next = rinsert(t, p->next);
else if(p->val > t){
p = new node(t, p);
n++;
}
return p;
}
void report()
{
int i, j;
for(i=0; i<bins; i++){
for(node *p=bin[i]; p!=sentinel; p=p->next){
printf("%d ", p->val);
}
}
printf("\n");
}
void genknuth(int m, int n)
{
int i;
for(i=0; i<n; i++){
if(bigrand() % (n-i) < m){
insert(i);
m--;
}
}
}
};
int main()
{
int m, n;
IntegerSetArray isa = IntegerSetArray();
IntegerSetList isl = IntegerSetList();
IntegerBST ibst = IntegerBST();
IntegerSetBins isb = IntegerSetBins();
IntegerBitVector ibv = IntegerBitVector();
printf("Input m and n:\n");
scanf("%d%d", &m, &n);
isa.genknuth(m, n);
isa.report();
isl.genknuth(m, n);
isl.report();
ibst.genknuth(m, n);
ibst.report();
isb.genknuth(m, n);
isb.report();
ibv.genknuth(m, n);
ibv.report();
return 0;
}