自己最近忙着软设的考试,重新看了一下数据结构的知识,从中发现自己的基本功还是不牢固。单单一个链表的问题,自己写了一段c++程序都调了很长时间才调通,所以复习还是很必要的。我就拿自己在调试的时候遇到的问题,说说我的一些体会吧。下面是我写的全部代码,这个是已经调试好的了,运行没有问题。
#include <iostream>
#include <string>
using namespace std;
typedef struct node
{
int data;
struct node *link;
}NODE,*LinkList;
class list
{
public:
LinkList head;
LinkList createlist();//创建链表
void displaylist();//链表结点的输出
int insertlist(int k,int elem);//将元素elem插入表中的第k个元素之前,若成功返回0,否则返回-1
int deletlist(int k);//删除表中的第k个元素节点,若成功返回0,否则返回-1
};
NODE *list::createlist()
{
NODE *p,*q;
p=new NODE;
q=new NODE;
int a[300];
char str[30];
int i=0;
head=NULL;
cout<<"请输入链表中的元素,以空格为分割(元素个数不能超过30):"<<endl;
cin.getline(str,30,'\n');
char* s=strtok(str," ");//以空格为分界符,使s指针指向空格之前的字符串。
while(s)
{
a=atoi(s); //将提取的字符创转化为整形
s=strtok(NULL," ");//每次找到空格分界符,一个NULL就放在分界符处,然后NULL就指向分界符之后的字符
i++;
}
for(int j=0;j<i;j++)//提取输入的每一个正整数
{
p->data=a[j];
if(j==0)
head=p;//让头指针指向第一个元素
else
{
q->link=p;//把p指向的结构体联入到链表的末尾
}
q=p;//q指针向后移动到末尾
p=new NODE;//再开辟一个节点空间。
}
delete p;
q->link=NULL;
return head;
}
void list::displaylist() //展示链表中的元素
{
NODE *p;
int i=1;
p=head;
while(p!=NULL)
{
cout<<"链表的第"<<i<<"个元素:";
cout<<p->data<<endl;
p=p->link;
i++;
}
}
int list::insertlist(int k,int elem)
{
NODE *p,*q;
if(k==1)
{
q=new NODE;
q->data=elem;
if(!q) return -1;
q->link=head;
head=q;
return 0;
}
else //查找表中的第k-1个元素,并且使p指向该元素节点
{
p=head;
int i=1;
while(p&&i<k-1)
{
p=p->link;
i++;
}
if(p&&i==k-1) //查到了表中的第k-1个元素
{
q=new NODE;
if(!q) return -1;
q->data=elem;
q->link=p->link;//让q的指针的list域指向第k个元素
p->link=q;//再让第k-1个元素的list域指向q指向的元素
return 0;
}
else return -1;
}
}
int list::deletlist(int k)
{
NODE *p,*q;
if(k==1) //删除的是头结点
{
p=head;
head=p->link;
delete p;
return 0;
}
else
{
p=head;
int i=1;
while(p&&i<k-1)
{
p=p->link;
i++;
}
if(p&&i==k-1) //查到了表中的第k-1个元素
{
q=p->link;
p->link=q->link;
delete q;
return 0;;
}
else return -1;
}
}
main()
{
list list1;
int k;
int elem;
//////////////创建链表///////////////
list1.head=list1.createlist();
list1.displaylist();
//////////////插入操作 //////////////////
cout<<"请输入要插入的元素位置:"<<endl;
cin>>k;
cout<<"请输入要插入的元素:"<<endl;
cin>>elem;
int insert_T=list1.insertlist(k,elem);
if(insert_T==0) cout<<"插入成功"<<endl;
else cout<<"插入失败"<<endl;
list1.displaylist();
//////////////删除操作///////////////////////
cout<<"请输入要删除的元素位置:"<<endl;
cin>>k;
int delete_T=list1.deletlist(k);
if(delete_T==0) cout<<"删除成功"<<endl;
else cout<<"删除失败"<<endl;
list1.displaylist();
}
下面我想说的是如果我更改一下程序的某个地方,不知道你能否看出错误在那哪?比如更改insertlist这个函数,如果我这样定义这个函数 :
//将元素elem插入表中的第k个元素之前,若成功返回0,否则返回-1 其中head1是链表的头指针。
int insertlist(ListLink head1,int k,int elem);
然后我就有head1代替head进行操作。你能猜到运行的时候会产生什么结果么?我想如果有对指针了解非常清楚的人都会想到,最终你不管插入什么,结果都没有正真的插入链表中。说的通俗点只是在inserlist这个函数中进行了一个插入的演示,这就好比函数的值传递问题,我想任何一个学习过程序设计语言的人都会知道,如果我调用函数chang(int x,int y)来交换x和y的值是不会达到你预期的结果的。同样上面的代码就如同chang(int x,int y)一样只不过操作数换成了指针而已。但是往往是因为换成了指针很多人都认为这是地址传递,从而认为已经修改了链表的头指针。其实不然,因为inserlist的函数中head1参数同样也是head的一个copy,它只不过是地址copy,其实和x,y的数值copy是一样的,只是换了种类型罢了。要正确完成此功能,需要传递链表头指针的地址。所以在写程序的时候千万不能来经验主意。不能一想传递的是指针就认为是函数的地址传递,想当然的认为在函数调用的时候就能修改想要得到的数值。这就提醒了我们看问题的时候一定要抓住问题的本质,不能只看表面的现象。