单链表中一个插入操作的分析
首先看链表的结构:p- >节点->节点....(单向),结点包括两部分,值value和指向下一节点的指针link,p为根节点,只有指针域,其类型为指向节点的指针,如要对其进行修改,调用函数时就要将其地址传给函数当实参,及函数的形参类型应为指向指针的指针。当在进行一些链表的操作时,如节点的插入,把一个节点插入到链表的起始位置必须作为一种特殊情况进行处理,因为我们要修改的是指向指针的指针,对于其他位置,我们需要修改的是节点的link字段,似乎我们在写对链表的操作时都要为此多写一段代码,但这两个看上去不同的操作实际上时一样的。
消除特殊的关键在于:我们必须认识到,链表的每个节点都有一个指向它的指针。对于第一个节点,这个指针就是根指针!对于其他节点,这个指针是前一个节点的link字段。重点在于每个节点都有一个指针指向它。至于该节点是不是位于一个节点的内部则无关紧要。
捋清思路之后给出解决方案:我们用一种和修改节点link字段完全一样的方式修改head变量,最后,在函数的指针变量中增加register声明,用于提高结果代码的效率。
附上《c和指针》中链表的插入操作,并简要解析一下,主要是指针的问题。
#include<stdio.h>
#include<stdlib.h>
#define FALSE 0
#define TRUE 1
typedef struct NODE//定义链表结构体
{
struct NODE *link;
int value;
}Node;
int insert(register Node **linkp,int new_value)
{
register Node *current;
register Node *new_node;
/*寻找插入位置,方法遍历链表,直到到达一个值大于或等于新值的节点*/
while((current=*linkp)!=NULL&¤t->value<new_value)
linkp=¤t->link;
/*为节点分配内存*/
new_node=(Node *)malloc(sizeof(Node));
if(new_node==NULL)
return FALSE;
new_node->value=new_value;
/*插入结点,返回true*/
new_node->link=current;
*linkp=new_node;
return TRUE;
}
/*以下是测试程序*/
main()
{
Node *head=NULL;//定义一个指向节点的指针,作为根节点
Node one,second;//初始化两个节点
head=&one;//使头指针指向首节点
if (head != NULL)
head->value=5;
head->link=&second;
(&second)->value=10;
// 显示链表
printf("第一节点:%5d,地址:%10d/n",head->value,&one);
printf("第二节点:%5d,地址:%10d/n",(head->link)->value,head->link);
printf("执行插入操作后:/n");
insert(&head,3);//调用insert函数
printf("第一节点:%5d,地址:%10d/n",head->value,&one);
printf("第二节点:%5d,地址:%10d/n",(head->link)->value,head->link->link);
printf("第三节点:%5d,地址:%10d/n",head->link->link->value,head->link->link->link);
printf("good~/n");
}
调试程序比较简单,下面分析一下insert()函数的执行过程。函数参数是一个指向节点的指针,和待插入的值,第一个参数之所以射出指向指针的指针,是为了采用传地址传值,这样才能返回链表的修改,实参用的是&head,即根节点的地址。执行插入操作时,先将指向根节点的指针的一份拷贝(不是指向根节点的指针!)和待插入数传给insert();遍历链表时先将head的值,即根节点的值也就是首节点的地址赋给current,此时curren和head同时指向首节点,紧接着开始判断,linkp随之后移动,current指针也移动(因为每次循环都执行current=*linkp)。完成查找后动态分配内存,生产新节点,将其指向current节点,*linkp指向它。
这里有一个小问题让我想了差不多two days,首先看insert函数,它执行时,将&head赋给linkp,采用的是地址传值,而函数的最后改变了*linkp(当插入的地方不是首节点),即改变了head 的值,这样返回后根节点也随之改变,这样链表结构不是被破坏了么?还是书有误?但事实证明,链表并没有破坏(见测试程序)。
最后经高人指点,上网各种查,问题解决,关键在于”linkp=¤t->link;“,即当遍历链表的时候,linkp以随之改变(当插入的地方不是首节点),指向的不再是根节点,最后的赋值时改变的也不是head的值,改变的是此时linkp指向的节点的link值,所以最终程序是正确的 这里谢谢聆雨轩★小潘,大奎 /ty 。
程序关键是指针的操作,指针弄明白了这个理解起来也比较容易。指针确实是c的一大难点,但也是c的一大特色。
写前面的文字和写调试后的文字中间差不多隔了一周,中间断断续续的调了一下,都有点想放弃这个程序了,《c和指针》也没往下看,进天终于通过了调试,心情比较舒畅,希望对学c的同学有用。
补充:软件开发 , C语言 ,