《大话数据结构》
先放上书中给出的标准代码:
/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(LinkList* L, int i, ElemType e)
{
int j;
LinkList p, s;
p = *L;
j = 1;
while (p && j < i) /* 寻找第i个结点 */
{
p = p->next;
++j;
}
if (!p || j > i)
return ERROR; /* 第i个元素不存在 */
s = (LinkList)malloc(sizeof(Node)); /* 生成新结点(C语言标准函数) */
s->data = e;
s->next = p->next; /* 将p的后继结点赋值给s的后继 */
p->next = s; /* 将s赋值给p的后继 */
return OK;
}
/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(LinkList* L, int i, ElemType* e)
{
int j;
LinkList p, q;
p = *L;
j = 1;
while (p->next && j < i) /* 遍历寻找第i个元素 */
{
p = p->next;
++j;
}
if (!(p->next) || j > i)
return ERROR; /* 第i个元素不存在 */
q = p->next;
p->next = q->next; /* 将q的后继赋值给p的后继 */
*e = q->data; /* 将q结点中的数据给e */
free(q); /* 让系统回收此结点,释放内存 */
return OK;
}
要分析的问题有以下:
- 为什么形式参数使用的是LinkList而不是LinkList*?
- 先给出以下结构体定义。
typedef struct Node{
ElemType data;
struct Node* next;
}Node;
typedef struct Node* LinkList; /* 定义LinkList */
-
- LinkList是一个结构体指针,之前书中提到过:
- 在顺序表中这句话是完全没毛病的,因为SqList是一个结构体的别名(非指针);但在链表中LinkList是一个结构体指针,它是等于Node*,保存的数值是一个结构体的地址;根据上面这段话的意思,需要改动时就要传递LinkList的指针,也就是LinkList*,指针的指针,即二维指针**;所以,在LinkList和LinkDelete中,都是
p=*L
,需要解引用才能得到头节点(结构体)的地址;如果是p=L
的话,得到的将会是一维指针的地址。 - 在传参时,也需要注意的是要传入的是指针的地址
&L
。 - 但其实这是不太必要的,先传入&,然后再使用*,到头来使用的还是结构体的地址。
可以直接传入L,接收时就不用写*,反正传的都是地址,对结果不会有什么影响。
- LinkList是一个结构体指针,之前书中提到过:
- 为什么
p=*L
,而不是让p=*L->next
?- 我对这个的理解是:有的时候虽然说要操作的是第i个元素,但是真正要寻找的是第i-1个元素(插入,删除等)。
- 以LinkInsert举例:
- 一开始的
j=1
,假如顺利的情况下,while循环结束的时候刚好j=i
,此时p->data
刚好是第i-1
个元素。
- 一开始的
- 在这两个函数中,对链表为空的情况是怎么处理的?
- 在ListInsert中,没有处理(本来也不需要处理)如果在链表为空的请款下,程序会跳过while循环(j==i),也会跳过
if (!p || j > i)
(p指向头节点,非空)。 - 不过给出了前提条件
- 所以压根就不用考虑空链表的问题。
- 如果只是在原有的代码修改下,判空处理和让p指向第一个i-1个元素是不能同时实现的。
- 但是在ListDelete中却可以实现判空处理,因为
if (!p->next || j > i)
条件中的是p->next
,当遇到链表的情况时符合条件。- 为什么ListDelete不能使用
if (!p->next || j > i)
呢?- 如果要插入的是最后一个元素,也会被这个条件带走,但最后一个元素后面虽然是NULL,但也是可以插入的。
- 为什么ListDelete不能使用
- 在ListInsert中,没有处理(本来也不需要处理)如果在链表为空的请款下,程序会跳过while循环(j==i),也会跳过
- 在while循环中,为什么LinkInsert中使用的是
p
,而在LinkDelete中使用的确实p->next
?- 因为ListInsert中,要插入的第i个元素可以为NULL;但是在删除时要删除的第i个元素却不能为NULL。