指针大法好,指针用得活,链表逆得好
首先方法是学别人的,在此讲一下思路和我犯的错误和思考
单链表麻烦的就是地址只掌握在前一个人手里,前一个人换票了,就没人找得到你了,所以极其不方便,然而指针就很能解决这个问题,因为它专业记地址,而且随便你设多少个指针都没关系
设三个指针p,q,r
p,q用来操作要逆转的两个结点,r用来记录q后面的结点地址,不然p,q玩去了,q后面的结点全部丢失.
头结点一视同仁,但是头结点的特殊很容易让后面的代码出问题
上张简单的图帮助理解
首先是r=q->next来记住q后面的结点
然后q->next=p完成逆转
要逆转的当然不止两个,这里又暴露了指针的好处
r=q->next; p=q; q=r就可以将三个指针往后挪一个然后同理继续操作
上代码
linklist reservelist(linklist &L)
{
linklist p,q,r;
p=L;
q=p->next;
p->next=NULL; //111
while(q)
{
r=q->next;
q->next=p;
p=q;
q=r;
}
return p;
}
代码中写三个一的地方非常重要,因为如果你把它去掉,输出时就会不停地输出一些很大地数,永无终结,这是因为链表逆转后,头结点成为了最后一个结点,最后一个结点的next 当然要是NULL,再说输出函数里,我们while里面的指针不为NULL就会一直循环
所以q记住头结点之后的结点地址后,L一定要设置L->next=NULL,代码中写了 //111的那一行也可以写成L->next=NULL
如果要用p来操作的话,一定要写在循环之前,因为循环后p早就不指示L了
接下来我们再看一下我们常用的输出函数
int show(linklist L)
{
linklist p;
p=L->next; //*
while(p) //**
{
printf("%d",&p->data);
p=p->next;
}
}
但是这个代码就一定正确吗?NO,它在这里会出问题,而且还不止一个问题
首先最后一个结点变成了第一个,所以// * 处应写为p=L;
其次头结点变成最后一个结点,但是它的数据域里是没输入东西的,所以while( p )这样循环的话,会把头结点的数据域输出一个很大的数,因此我们应该让它少循环一次,把//**处的while( p)改成while(p->next)即可