之前看数据结构时,以为链表操作很容易,真正写代码时才发现被打脸了。。。经历了各种错误后,现在总结一下走过的弯路。
这里主要说下链表的增加删除节点操作。
typedef struct lnode
{
int data;
struct lnode *next;
}lnode,*llist;
以上是我定义的节点结构,比较简单,不再赘述。
下面说下犯的错误
错误1. addnode函数为增加节点操作
void addnode(lnode *lst,int value)
{
lnode *p=new lnode();
p->data=value;
p->next=NULL;
if (lst==NULL) {
lst=p;
return;
}
lnode *q=lst;
while (q->next) {
q=q->next;
}
q->next=p;
}
好吧,上面属于低级错误,但是一遇到指针就有些搞不清楚。所以这里想总结一下。
lst为存放lnode结构体地址的指针,初始值为空,在addnode函数体内,对lst赋值,lst改变,但是出了函数,lst仍然为原来值,这是典型的值传递(lst内容即地址的值传递),行参的改变不影响实参。如果是基本变量,没有搞错过,but加了个指针就搞混了。。所以为了改变实参,这里采用了指针传递。
错误2.
void addnode(llist *lst,int value)
{
lnode *p=new lnode();
p->data=value;
p->next=NULL;
if (lst==NULL) {
*lst=p;
return;
}
lnode *q=*lst;
while (q->next) {
q=q->next;
}
q->next=p;
}
对待二维指针,一定要认真搞清楚哪个变量指向什么
lst结构如图所示,lst是地址,地址中存放的内容*lst为p的地址,p中存放的内容*p为lnode的地址。
错误2就在于没有搞清lst=null和*lst=null的区别。
lst=null也就是lst指向0x0000000000000000地址(内核地址,不能访问),此时,可以对lst另赋值,让lst指向其他地址,但是不能改变*lst 。
所以,正确的做法应该是判断*lst是否为null,此时lst为自己的地址,*lst内存放的是p的地址,若*lst为null,则说明p为空,即没有指针指向链表,即链表为空。
经历了以上两次错误,最终得到正确答案,在进行插入操作时,要注意链表为空的情况;删除时,也需要注意删除第一个节点的情况。
正确代码:
void addnode(llist *lst,int value)
{
lnode *p=new lnode();
p->data=value;
p->next=NULL;
if (*lst==NULL) {
*lst=p;
return;
}
lnode *q=*lst;
while (q->next) {
q=q->next;
}
q->next=p;
}
void deletenode(llist *p,int value)
{
if (p==NULL||(*p)==NULL) {
return;
}
else
{
lnode *q=*p;
lnode *r=q;
if (q->data==value) {
*p=q->next;
delete q;
q=NULL;
return;
}
while (q->next && q->data!=value) {
r=q;
q=q->next;
}
if (q->data==value) {//判断最后一个节点是否为value
r->next=q->next;
delete q;
q=NULL;
}
}
}