查找专题讨论
一、查找专题讨论
题目1-集合容器设计(不许用STL)
1.需要设计一个容器,该容器的特点是可存放唯一元素(即,相同的元素只能存放一个)。为了实现简单,暂时只考虑存放整数的情况
a.如何实现?判断元素唯一性的时间复杂度是多少?
实现:
定义一个容器结构体,结构体中含三个整数数组,其中两个数组,以出现的元素为数组下标,保存出现的该元素的出现次数,一个保存出现的正数元素次数,一个保存出现的负数元素次数;最后一个数组则保存出现的元素;之外,结构体中还含有两个整数保存存放的正、负元素个数。
结构体:
#define MAXNUM 4294967296//因为题目要求只考虑存放整数的情况,而整型的取值范围为-2147483648到2147483647,所有将最大值设为两倍的2147483648
typedef struct{
int Element[MAXNUM];//存放题目要求存放的元素
int JudgePos[MAXNUM]={0};//以出现的元素当做数组下标,保存每个非负数元素出现的次数,判断相同的元素出现的次数是否只有一个
int JudgeNeg[MAXNUM]={0};//同上,保存每个负数元素出现的次数,判断相同的元素出现的次数是否只有一个
int CountPos=0,CountNeg=0;//一个保存已存放的非负数的元素个数,一个保存已存放的负数的元素个数
}muster;
判断并存放元素:
int insert(muster &S,int i)
{
int Count=S.CountPos+S.CountNeg;
if(i<0)//判断要存放的整数正负
{
i=-i;//因为数组下标要求为正数,而整数位负数则
if(S.JudgeNeg[i]!=0)//判断是否该元素是否有出现过
return 0;
S.Element[Count]=-i;//将该元素存入数组中,因为原本元素为负数,而之前的代码中为了判断该元素是否存在将其变为了正数,但element是保存原来要求输入的数的,所以要将其再变为负数
S.JudgeNeg[i]++;//负数元素数组记录出现次数
S.CountNeg++;//负数元素个数增加
}
else
{
if(S.JudgePos[i]!=0)
return 0;
S.Element[Count]=i;//因为输入数为正数,不需要转换下标正负,也不需要再转换回来
S.JudgePos[i]++;
S.CountPos++;
}
return 1;
}
以原数组存放元素为0,存入2,-2两值为例:



所以判断元素唯一性的时间复杂度为O(1);
相关代码:
int judge(muster S, int i)
{
if (i < 0)
{
i = -i;
if (S.JudgeNeg[i] != 0)
return 0;
else
return 1;
}
else
{
if (S.JudgePos[i] != 0)
return 0;
else
return 1;
}
}
b.将元素放入该容器后,可将容器中的元素依次取出,如果不要求依次取出的元素按值大小排序。则该容器内部如何实现?
即按顺序输出Element数组值。
void PrintfElement(muster S)
{
int Count = S.CountNeg + S.CountPos;//所有已保存元素的个数
for (int i = 0; i < Count; i++)
{
cout << S.Element[i] << " ";
}
}
c.如果从该容器中依次取出的元素可按照值排序,应该如何实现?为什么需要这样的一个容器?有什么用?
·按值排序:
因为Judge数组下标保存所有元素,所以可以通过循环元素数组所有下标,根据数组中所对应的该值是否存在来判断是否输出,并且根据正负数排序不同,所以循环条件也不同。
void OrderPrinf(muster S)
{
int i, n1,n2;
if (S.CountNeg != 0)//判读有无负数元素
{
for (i = 0, n1 = MAXNUM; i < S.CountNeg; n1--)//将所有元素遍历,如果存在,则输出
{
if (S.JudgeNeg[n1] == 1)
{
n2 = -n1;//因为n1还要进行循环,所以用n2来输出
cout << n2 << " ";
S.CountNeg--;//通过输出数的个数与统计保存的元素个数是否相同来看做循环条件
}
}
}
if (S.CountPos != 0)//判断有无正数元素
{
for (i = 0, n1 = 0; i < S.CountPos; n1++)
{
if (S.JudgePos[n1]== 1)
{
cout << n1 << " ";
S.CountPos--;
}
}
}
}
b与c不同的地方:
b是循环Element数组,而c是循环两个Judge数组;
但循环结束条件都是输出的元素个数等于统计的元素个数时。
·需要这样的容器的原因:因为这样的容器可以保存数据且保证没有相同的元素;
·作用:统计多种重复数据中的所含的元素种类与个数,或是在多种重复元素分配的题目中比较所出现的元素种类是否符合要求等。
eg图着色问题

对于颜色出现的种类数受限问题
int a[501] = { 0 }, b[501] = { 0 };//a数组保存颜色,b数组统计出现次数并进行判断
for (i = 1; i <= v; i++) {
cin >> a[i];
b[a[i]]++;
if (b[a[i]] == 1) {//与原本中的结构容器不同,相同元素会重复出现,所以在其第一次出现的时候进行统计
count++;
}
}
d.写出该容器常用方法时间复杂度
·插入元素:O(1);
·取出所有元素:O(n);
·删除单个元素:O(1);
由上面插入与取出元素的代码可知,元素统计数是根据CountNeg+CountPos,而元素种类是根据Judge数组的下标,所以删除代码改变这两个的数值即可。
void Delete(muster& S, int i)
{
if (i<0)
{
i = -i;
S.JudgeNeg[i] = 0;
S.CountNeg--;
}
else
{
S.JudgePos[i] = 0;
S.CountPos--;
}
}

进阶:
如果放入容器的值不仅包含数值型,还包含其他类型,比如字符串型,怎么实现?
实现:与上面类似
定义的结构体中包含三个整数数组与一个字符数组,两个整数。
typedef struct
{
int ElementInt[MAXNUM];//保存出现的整数
int JudgePos[MAXNUM] = { 0 };//保存每个非负数元素出现的次数,判断是否相同的元素只有一个
int JudgeNeg[MAXNUM] = { 0 };//保存每个负数元素出现的次数,判断是否相同的元素只有一个
char ElementChar[MAXNUM];//保存出现的字符
int JudgeChar[MAXNUM] = { 0 };//根据ASCII码,判断是否相同的字符只有一个
int CountPos = 0, CountNeg = 0, CountChar = 0;
}MulMuster;

浙公网安备 33010602011771号