1.当L==NULL的时候是不能执行NULL->data、NULL->Next、等等的一系列的代码,因为NULL是个只读的地址,不允许写数据,碰到->运算符也会导致程序崩溃,所以所有代码如果涉及指针,他一定会在函数刚进来的地方就做检查,检查传进来的指针是不是NULL。在后续的代码中也要不断小心谨慎,任何类似于L->NEXT->NEXT的二级运算都是危险的,因为L不是NULL不代表L->NEXT不是NULL
2.一个void函数,居然能return ERROR,这是我始料未及的。我学编程才一年,见识的比较少,我一直以为void函数是不能返回任何元素的。。。我只知道可以Exit(-1)这样让程序显示异常终止,return ERROR没见过。有机会帮我请教一下。
3.
p->data 取p指针所指结构体的data成员
<data 和data比较大小(至于这个
data哪来的,至少你给的这部分函数里是没有了,可能是个全局变量。但我在看到
//-4
的笔误之后意识到,你们老师估计又笔误了,因为这个Inset函数有个形参 e 他由始至终没用过。而通常在一个插入函数中,这个e就会是即将被插入的元素才是)
(p->next!=NULL) 这和我在1中提到的L->next->next讲的是一件事。就是确保p->next!=NULL了才允许执行p=p->next;再到下一个循环的p->data.
4.p=L这是个赋值语句,在if()里面做条件判断的话,他是先把L指针赋值给p指针,然后当p!=NULL就返回true,否则返回false.我赌1厘,这是你们老师的笔误,他肯定是要写p==L,因为当程序执行到那一行的时候,L本身就不可能是NULL,换句话说这个if()是永恒成立的。
撇开笔误,我们谈谈
p==L 它表示当前遍历到到的指针所指的元素和传递进来的链表表头是同一个元素,也就是说
// ->3 所标记的那个while循环必须从一开始就不成立,没执行过
p=p->next p==L才是true。
L是什么,L是表头啊,这就表示旧的链表要链接到即将插入的元素之后。 处理链表头结点和处理链表中间的结点是不一样的嘛。这个你应该知道吧。。
程序代码:
void InsertList(LinkList L,int e)
{
if(L==NULL)// ->1. 当链表为空,输出提示并使程序错误终止
{
printf("线性表为空");
return ERROR;// ->2
}
int i=0;
Node *s,*p,*ptr; //ptr指向即将被插入的元素的父节点
s=(Node *)malloc(sizeof(Node)); //s创建生成一个新节点,这儿结点就是待会要用来插入的
p=L; //p指针用于在L链表中遍历,寻找合适的插入位置
s->data=data;
while((p->data<data)&&(p->next!=NULL))// ->3.
{
ptr=p; // ptr保留被遍历到的元素的父节点,用于 //-5
p=p->next;
i++;
}
if(p->data>=data)// >=data '>=' 和前面的 '>' 一样,是比较运算符,比大小的
{
if(p=L)// ->4 将新插入的元素作为头结点,把旧的链表链接过来
{
s->next=p;
L->next=s;
}
else //插入元素到链表中间某处或链表尾部
{
s->next=p;
ptr->next=s; // ->5
}
}
else
{
p->next=s;
s->next=NULL;
}
printf("插入成功");
}
这是个跑不起来的程序,估计你们老师也是“纸上编程”,根本就没运行调试吧。当然,我没看到完整的一个程序代码,仅凭一个函数说这话,也是很不负责任的。原则上,如果你怀疑你老师有可能写错了,那么你可以把Insert函数的(int e)修改为(int data),
if(p=L)修改为if(p==L)
这样的话,这个Insert函数所实现的就是根据读入的数据大小,每插入一个数据都保存该链表是非递减(从小到大)有序。不过,要求L本身带有数据,对于空链表,这个程序是不能正确执行的。
[此贴子已经被作者于2016-9-29 18:46编辑过]