否则一旦提取改变p后的下一个节点位置就丢失了。
每一个节点都有两段关系,它的前驱和后继,头节点只有后继。在做插入或删除时,某个节点的改变对应着相邻两个节点的改变,上一个节点的后继改变,下一个节点
的前驱改变,这些在操作时一定要注意。
说说我自己犯的一个低级错误,在遍历链表时,p=p->next忘了写。其他复杂的操作完成了,一激动,最普通的指针移动到下一个节点没了,这么多操作也没的循环了就
欺负欺负当前一个节点,所以千万记得做完操作后p=p->next让下一个节点也能享受到应有的操作。
Runtime error,越界,我所有的程序几乎都出现过这个毛病。要么是遍历的时候用到p->next->val,然而p已经是最后一个节点,p->next当然没得找。还有就是没有申请
空间,ListNode *dummy;dummy=new ListNode(0);第二句代码前就不要加*了。当然还有更low的没加括号,这些低级错误在刚开始用时困扰了我好久,慢慢的写熟练了这
些低级错误也就消失了。
很多时候都需要返回链表,这时就需要事先保存一个头节点,因为现在用的节点经常随着遍历已经走到了后边,头节点的用处是极大的,头插法就是建立在此基础之上。
然而按照一般的逻辑思维我们加东西都是依次往后加,因此尾插法更符合我们通常的思考方式。
ListNode *node;
node=new ListNode(0);
rear->next=node;
rear=node;
node=new ListNode(0);
rear->next=node;
rear=node;
如果不是已经有的节点新插入也每一个节点也都是需要申请空间的,申请一个往尾巴后面加一个,然后尾巴指向后一个,永远保证rear尾巴是最后一个节点,让新来的站在
他身后,就像弟弟妹妹一样,每多一个新节点小尾巴就是最新来的那个。
在对链表遍历的while循环中要加一个控制结束的条件如head!=NULL,这里要注意head是头节点还是第一个节点,如果是头节点还需要head->next!=NULL,这个
head和head->next也是经常导致我犯迷糊的原因,写着写着就不知道需要的是哪个节点了。这时候就需要借助测试数据把自己的程序捋一遍,走到哪里断了,把这里的路修好,
继续走,先改好程序的编译错误才能为后面修改程序时加上自己没考虑到的部分打好基础。
链表相比数组的特点就是用逻辑关系代替连续存储空间。如数组1 2 3 4 5若把3移动到5后面变为1 2 4 5 3需要依次改变很多,而链表只需要改一下关系让2->next=4,5->next=3
即可。我认为链表中最厉害的一句,*p=*(p->next),o(1)算法,不用再一个个的改前驱后继的关系,就直接覆盖。由此也能看出来p->next有多强大。
最后附上我做10个链表题的情况,一是为老师检查作业用,二是勉励自己,看看那傻乎乎的compile error,提醒自己盖房子先把框架定好了;看看那红色的runtime error,提醒自己不要再犯类似的错误;看看那痛苦的wrong answer,永远有你没有考虑到的数据是错误的,最后,绿色的AC,那是我渴求的阿瓦隆。