4.已知一个单链表中的数据元素含有三类字符(即字母字符,数字字符和其它字符),试编写算法,构造三个循环链表,使每个循环链表中只含有同一类的字符,且利用原表中的结点空间作为这三个表的结点空间。
大概思路:只有字母,数字和其他字符,可以用char型存储单链表中的数据元素,最后根据ASCII码把元素分为字母,数字,其他三类。由于有三个类,循环链表,需要三个头指针,三个尾指针(尾指针可要可不要,此处是个人习惯),一个记录下一个结点地址的指针
难点:利用原表的结点空间作为三个表的结点空间
ASCII码:48~57表示0~9数字。10,11等两位数以上的数字ASCii码不能直接表示,不过由于该单链表是逐个字符存储的,所以不需要考虑检测两位数以上的数字和负数
65~90 表示A~Z,97~122表示a~z,0~127内的其他数字表示其他字符
template<class T>
bool List4<T>::divede_them_into_three(){
List4_link<T> *p1;//用来判断当前结点数据类型
if(first==NULL)
{ cout<<"空表!";
return false;}
p1=first;
while(p1!=NULL)
{
p=p1->next;//记录p1的下一个结点,防止地址丢失
if(p1->data>=48&&p1->data<=57)
{
if(num_number==0)
{
first_number=p1;
tail_number=first_number;
}
else
{
tail_number->next=p1;
tail_number=p1;
}
num_number++;
}
else if((p1->data>=65&&p1->data<=90)||(p1->data>=97&&p1->data<=122))
{
if(num_number==0)
{
first_alpha=p1;
tail_alpha=first_alpha;
}
else
{
tail_alpha->next=p1;
tail_alpha=p1;
}
num_alpha++;
}
else{
if(num_else==0)
{
first_else=p1;
tail_else=first_else;
}
else
{
tail_else->next=p1;
tail_else=p1;
}
num_else++;
}
p1=p;
}
tail_number->next=first_number;
tail_alpha->next=first_alpha;
tail_else->next=first_else;//形成循环链表
return true;
}
没想到会这样报错:
这个文件我根本没创建过,莫名其妙地运行了
难道是Xcode的缓存要清除?需要找到Library/Developer/Xcode/DerivedData,看来看去没有Library,被隐藏了,点开用户文件夹,选择显示‘资源库’文件夹,找到‘DerivedData’文件夹,文件夹内是模拟器运行每个APP生成的缓存文件,全都删了
没用,无奈重建了一个project
重建了一个project正常运行了一段时间,也出现了上述问题,瞎搞一通解决了,目前测试出来的原因是没有把测试用的cpp文件和头文件放在一个文件夹里
这样放置文件问题解决
其他没什么问题,析构函数要重写,调用divide_them_into_three()前后的析构函数是不一样的
重写的析构函数出了大问题(加一个判断条件,再套三次模板):
template<class T>
List4<T>::~List4(){
List4_link<T> *pr;
if(first==NULL)
{ exit(1);}//无论是否调用divide,first都不会为空
if((first_number!=NULL)||(first_alpha!=NULL)||(first_else!=NULL))
{
if(num_number==1)
{ delete first_number;
}
else
{ pr=first_number->next;
while(first_number!=NULL)
{
delete first_number;
first_number=pr;
pr=pr->next;
}
}
if(num_alpha==1)
{ delete first_alpha;
}
else
{ pr=first_alpha->next;
while(first_alpha!=NULL)
{
delete first_alpha;
first_alpha=pr;
pr=pr->next;
}
}
if(num_else==1)
{ delete first_else;
}
else
{ pr=first_else->next;
while(first_else!=NULL)
{
delete first_else;
first_else=pr;
pr=pr->next;
}
}
}
else
{ if(num==1)
{ delete first;
}
else
{ pr=first->next;
while(first!=NULL)
{
delete first;
first=pr;
pr=pr->next;
}
}
}
}
看来是释放了两次某空间
错因:忘了是个循环链表,析构函数判断条件不该是头结点为空
改成这样就好(以字母链表为例)
while(num_alpha!=0)//num_alpha在类中用于记录字母链表结点数
{
delete first_alpha;
first_alpha=pr;
pr=pr->next;
num_alpha--;
}
总结:析构函数和构造函数随着链表链接方式而改变
5.试编写一个算法,找出一个循环链表中的最小值并删除。
大概思路:弄两个变量AB,A记最小值,不断和下一个结点的数据比,B记录A当前数据是第几个结点的数据,还要考虑删除头结点尾结点中间结点
出现了一个很有意思的问题:在类的public成员函数中,cur_num赋值失败,为什么?
int min,cur_num,count=0;//min记最小数据,cur_num记min中记录的是第几个结点的数据,count记遍历了几个结点
while(count!=num)
{
++count;
min=first->data;//min不能初始化为任何数字
if(p->data<min)
{
min=p->data;
cur_num=count;//cur_num不会被赋值,为什么?
}
cout<<min<<" "<<cur_num<<" ";
p=p->next;
}
测试了一下,问题出在count,即使达到了count==num的条件,该循环也没有break,为什么?
输出语句改为
cout<<min<<" "<<cur_num<<" "<<count;
得到:
为什么count加了10?
再改一下循环,使count不进行任何运算,仅在循环前赋予初值0,得到:
说明赋值语句对count同样无效,why?
没想通,先睡觉
酒醒了,是min的初始化语句有问题,要放在循环外,否则无论遍历几遍,min的值始终是头结点的值,所以不是不能给cur_num赋值,产生这种情况有两个原因:1⃣️我测试的数据头结点即为最小,所以该循环不会进入if的判断语句中给cur_num赋值2⃣️cur_num未初始化
正确的代码:
template<class T>
bool List5<T>::find_min()//注意是循环链表
{
if(first==NULL)
{
cout<<"空表!";
return false;
}
List5_link<T> *p,*p_mid,*p_last;
p=first;
min=first->data;//min不能初始化为任何数字,只能为第一个的值
while(count1!=num)//count1用于记录遍历了几个结点
{
++count1;
if(p->data<min)
{
min=p->data;
cur_num=count1;
}
p=p->next;
}
p=first;
count1=0;
if(cur_num==0)//删除头结点
{
p=first->next;
delete first;
first=p;
tail->next=first;//循环链表
}
else
{
while(count1!=cur_num-2)//p停在要删除的结点前一位,p_mid要删除的结点,p_last要删除的结点后一位
{//解释一下cur_num-2,因为cur_num最小值为0
p=p->next;
p_mid=p->next;
p_last=p_mid->next;
count1++;
}
if(cur_num==num)
{
delete tail;
tail=p;
tail->next=first;
}
else
{
delete p_mid;
p->next=p_last;
}
}
num--;
return true;
}