一、用数组来表示集合
其中在插入函数中先调用二分查找,找出要插入的元素t,如果不存在就返回其前一个位置,先将其+1然后进行插入。
#include<iostream>
using namespace std;
class IntSet
{
int Size;
int *A;
public:
IntSet(int n,int _Size=0)
{
A=new int[n];
Size=_Size;
}
void insert(int t);
int find(int t);
int size(){return Size;};
void report(int *r);
};
void IntSet::insert(int t)
{
int i=find(t);
if(i>=0 && A[i]==t)
return ;
i++;//插入在第一比当前值小的位置的后面
for(int j=Size;j>i;j--)
A[j]=A[j-1];
A[i]=t;
Size++;
}
int IntSet::find(int t)
{
int lo=-1,hi=Size;
while(lo+1!=hi)
{
int mid=lo+((hi-lo)>>1);
if(A[mid]<=t)
lo=mid;
else
hi=mid;
}
return lo;
}
void IntSet::report(int *r)
{
for(int i=0;i<Size;i++)
r[i]=A[i];
}
int main()
{
int N=100,M=10;
IntSet s(M);
while(s.size()<M)
s.insert(rand()%N);
int *report=new int[M];
s.report(report);
for(int i=0;i<M;i++)
cout<<report[i]<<endl;
system("pause");
return 0;
}
二、用链表来表示集合:
在程序中,用了3个insert函数,第一个是普通的插入,第二个是用指向指针的指针来进行插入,练习题中第4题就是这样来做,可以很明显看出代码缩短了,判断语句大大减少。第三个是用一次new来代替多次new,如练习题中第5题就是这样做的。下面一片博文我会分析在动态分配内存时,分配相同内存,但是用不同次数分配的消耗时间的差异。
#include<iostream>
using namespace std;
struct Node
{
int val;
Node *next;
Node(int _val=0,Node *_next=NULL):val(_val),next(_next){}
};
class IntSet
{
int Size;
Node *head;
Node *freeNode;
public:
IntSet(int n=0)
{
head=new Node(INT_MAX);
Size=0;
freeNode=new Node[n];
}
void insert(int t);
void insert1(int t);
void insert2(int t);
int size(){return Size;};
void report(int *r);
};
void IntSet::insert(int t)
{
if(head->val==t)
return ;
Node *curr=head;
if(head->val>t)
{
head=new Node(t,curr);
Size++;
return;
}
for(;curr->next->val<t;curr=curr->next);
if(curr->next->val==t)
return;
Node *temp=curr->next;
curr->next=new Node(t,temp);
Size++;
}
void IntSet::insert1(int t)
{
Node **p=&head;
for(;(*p)->val<t;p=&((*p)->next));
if((*p)->val==t)
return ;
*p=new Node(t,*p);
Size++;
}
void IntSet::insert2(int t)
{
Node **p=&head;
for(;(*p)->val<t;p=&((*p)->next));
if((*p)->val==t)
return ;
Node *temp=*p;
*p=freeNode++;
(*p)->val=t;
(*p)->next=temp;
Size++;
}
void IntSet::report(int *r)
{
Node *curr=head;
for(int i=0;i<Size;i++)
{
r[i]=curr->val;
curr=curr->next;
}
}
int main()
{
int N=100,M=10;
IntSet s(M);
while(s.size()<M)
s.insert(rand()%N);
int *report=new int[M];
s.report(report);
for(int i=0;i<M;i++)
cout<<report[i]<<endl;
IntSet s1;
while(s1.size()<M)
s1.insert1(rand()%N);
// int *report=new int[M];
s1.report(report);
for(int i=0;i<M;i++)
cout<<report[i]<<endl;
IntSet s2(M);
while(s2.size()<M)
s2.insert2(rand()%N);
// int *report=new int[M];
s2.report(report);
for(int i=0;i<M;i++)
cout<<report[i]<<endl;
system("pause");
return 0;
}
三、二分搜索树
用了三个版本的插入,同上所述,一个是每次插入都用一次new,另一个是用一次new把空间全开出来,最后一个插入了一个哨兵,并且将每一个节点的为空的left或right指针,指向哨兵,用指向指针的指针来遍历,减少了代码长度,如下可以清晰看出代码长度的变化。
#include<iostream>
using namespace std;
struct Node
{
int val;
Node *left,*right;
Node(int _val=0,Node *_left=NULL,Node *_right=NULL)
{
val=_val;
left=_left;
right=_right;
}
};
class IntSet
{
int Size;
Node *root;
Node *freeNode;
Node *sharedNode;
public:
IntSet(int n=0)
{
Size=0;
freeNode=new Node[n];
sharedNode=new Node;
root=sharedNode;
}
void insert(int t);
void insert1(int t);
void insert2(int t);
int size(){return Size;};
void report(int *r);
void traverse(Node *p,int *r,int &i);
void report_share(int *r);
void traverse_share(Node *p,int *r,int &i);
};
void IntSet::insert2(int t)
{
sharedNode->val=t;
Node **curr=&root;
while((*curr)->val!=t)
{
if((*curr)->val>t)
curr=&((*curr)->left);
else
curr=&((*curr)->right);
}
if((*curr)!=sharedNode)
return ;
*curr=freeNode++;
(*curr)->val=t;
(*curr)->left=sharedNode;
(*curr)->right=sharedNode;
Size++;
}
void IntSet::insert1(int t)
{
if(root==NULL)
{
root=new Node(t);
Size++;
return;
}
Node *curr=root;
while(curr!=NULL)
{
if(curr->val==t)
return ;
if(curr->val>t)
{
if(curr->left==NULL)
{
Size++;
curr->left=freeNode++;
curr->left->val=t;
return;
}
curr=curr->left;
}
else
{
if(curr->right==NULL)
{
Size++;
curr->right=freeNode++;
curr->right->val=t;
return;
}
curr=curr->right;
}
}
}
void IntSet::insert(int t)
{
if(root==NULL)
{
root=new Node(t);
Size++;
return;
}
Node *curr=root;
while(curr!=NULL)
{
if(curr->val==t)
return ;
if(curr->val>t)
{
if(curr->left==NULL)
{
Size++;
curr->left=new Node(t);
return;
}
curr=curr->left;
}
else
{
if(curr->right==NULL)
{
Size++;
curr->right=new Node(t);
return;
}
curr=curr->right;
}
}
}
void IntSet::report(int *r)
{
int i=0;
traverse(root,r,i);
}
void IntSet::traverse(Node *p,int *r,int &i)//此处的i要用引用
{
if(p->left!=NULL)
traverse(p->left,r,i);
r[i++]=p->val;
if(p->right!=NULL)
traverse(p->right,r,i);
}
void IntSet::report_share(int *r)
{
int i=0;
sharedNode->val=INT_MAX;
traverse_share(root,r,i);
}
void IntSet::traverse_share(Node *p,int *r,int &i)//此处的i要用引用
{
if(p->left->val!=INT_MAX)
traverse_share(p->left,r,i);
r[i++]=p->val;
if(p->right->val!=INT_MAX)
traverse_share(p->right,r,i);
}
int main()
{
int N=100,M=10;
IntSet s(M);
while(s.size()<M)
s.insert2(rand()%N);
int *report=new int[M];
s.report_share(report);
for(int i=0;i<M;i++)
cout<<report[i]<<endl;
IntSet s1;
while(s1.size()<M)
s1.insert(rand()%N);
// int *report=new int[M];
s1.report(report);
for(int i=0;i<M;i++)
cout<<report[i]<<endl;
system("pause");
return 0;
}
四、位向量操作
在此处一定要注意初始化,当给A开辟空间后,进行初始化为0。
#include<iostream>
using namespace std;
class IntSet
{
int Size;
int *A;
int N;
public:
enum{ BITSPERWORD=32,SHIFT=5,MASK=0x1F};
IntSet(int n=0)
{
Size=0;
N=n;
A=new int[1+(n>>SHIFT)];
for(int i=0;i<1+(n>>SHIFT);i++)
A[i]=0;//注意这里必须要先初始化
}
void setValue(int t)
{
A[t>>SHIFT]|=1<<(t&MASK);
Size++;
}
void clrValue(int t)
{
A[t>>SHIFT]&=~(1<<(t&MASK));
Size--;
}
bool test(int t)
{
return A[t>>SHIFT]&(1<<(t&MASK));
}
void report(int *r)
{
int k=0;
for(int i=0;i<N;i++)
{
if(test(i))
r[k++]=i;
}
}
int size(){return Size;}
};
int main()
{
int N=100,M=10;
IntSet s(N);//使用了1+n/32的内存
while(s.size()<M)
s.setValue(rand()%N);
int *report=new int[M];
s.report(report);
for(int i=0;i<M;i++)
cout<<report[i]<<endl;
system("pause");
return 0;
}
五、箱操作
其实这就是一种简单的散列,和求模的散列类似,只是这里往箱子中插入数据时要保证数据的顺序性,这样在输出时候才能保证是顺序的随机数。
#include<iostream>
using namespace std;
struct Node
{
int val;
Node *next;
Node(int _val=0,Node *_next=NULL):val(_val),next(_next){}
};
class IntSet
{
int Size;
Node **A;
int nBox;
int maxVal;
int minVal;
public:
IntSet(int _maxVal,int _minVal=0)
{
maxVal=_maxVal;
minVal=_minVal;
Size=0;
nBox=1+(maxVal-minVal)/10;
A=new Node*[nBox];
for(int i=0;i<nBox;i++)
A[i]=new Node(INT_MAX);
}
void insert(int t)
{
int boxNum=(t-minVal)/nBox;
Node **curr=&A[boxNum];
while((*curr)->val<t)
curr=&((*curr)->next);
*curr=new Node(t,*curr);
Size++;
}
void report(int *r)
{
int k=0;
for(int i=0;i<nBox;i++)
{
Node *curr=A[i];
while(curr->val!=INT_MAX)
{
r[k++]=curr->val;
curr=curr->next;
}
}
}
int size(){return Size;}
};
int main()
{
int N=100,M=10;
IntSet s(100);
while(s.size()<M)
s.insert(rand()%N);
int *report=new int[M];
s.report(report);
for(int i=0;i<M;i++)
cout<<report[i]<<endl;
system("pause");
return 0;
}