稍微记录一下接下来复习的一些想法。
这两天开始复习王道的数据结构,又看到了关于链表的中间插入的代码。
书籍中在插入的函数传递参数时,使用的C++的引用类型,具体可以参照《C++ Primer Plus》中的解释。
王道书籍中描写中间插入时是这样的:
当时就衍生出一个疑问,L是指针类型,存放的是地址,对于普通的函数形参传递,即值传递,将会在函数内开辟内存空间以创建并初始化形参变量,这就意味着函数内部的形参将不再与外界传递的实参内存地址等同。而对于指针而言,就是内部和外部的指针的地址不一致,但是实际上对于指针内存放的值也就是节点的地址是无影响的,这也就是意味着在中间插入时无论我是否指定引用,都会完成节点的中间插入而更新原实参L链表。
更形象的来说,相当于外界有一个原链表指针L指向节点A,而进入函数之后,发生局部变量创建复制,无非是多了另外一个不同指针本身地址的链表指针L1指向节点A,即L和L1两个链表指针所存储的值是相同的。从最后的插入结果来看,所以无论是否使用引用都是可以完成的。
整体代码如下(比较懒,就使用了数据结构之单链表(c语言附完整代码)_数据结构_hello_world&&-GitCode 开源社区代码做一下测试):
#include <stdio.h>
#include <malloc.h>
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next; //指向后继结点
} LinkNode; //声明单链表结点类型
void CreateListR(LinkNode *&L,ElemType a[],int n)
//尾插法建立单链表
{
LinkNode *s,*r;
L=(LinkNode *)malloc(sizeof(LinkNode)); //创建头结点
L->next=NULL;
r=L; //r始终指向终端结点,开始时指向头结点
for (int i=0;i<n;i++)
{
s=(LinkNode *)malloc(sizeof(LinkNode));//创建新结点s
s->data=a[i];
r->next=s; //将结点s插入结点r之后
r=s;
}
r->next=NULL; //终端结点next域置为NULL
}
void InitList(LinkNode *&L)
{
L=(LinkNode *)malloc(sizeof(LinkNode)); //创建头结点
L->next=NULL;
}
bool ListEmpty(LinkNode *L)
{
return(L->next==NULL);
}
int ListLength(LinkNode *L)
{
LinkNode *p=L;int i=0;
while (p->next!=NULL)
{ i++;
p=p->next;
}
return(i);
}
void DispList(LinkNode *L)
{
LinkNode *p=L->next;
while (p!=NULL)
{ printf("%d ",p->data);
p=p->next;
}
printf("\n");
}
bool ListInsert(LinkNode *L,int i,ElemType e)
{
printf("插入中链表地址:%d\n",&L);
printf("插入中链表的头节点地址:%d\n",L->next);
int j=0;
LinkNode *p=L,*s;
if (i<=0)
return false; //i错误返回假
while (j<i-1 && p!=NULL) //查找第i-1个结点p
{ j++;
p=p->next;
}
if (p==NULL) //未找到位序为i-1的结点
return false;
else //找到位序为i-1的结点*p
{ s=(LinkNode *)malloc(sizeof(LinkNode));//创建新结点*s
s->data=e;
s->next=p->next; //将s结点插入到结点p之后
p->next=s;
return true;
}
}
int main()
{
LinkNode *L;
ElemType e;
ElemType a[]={1,2,3,4};
CreateListR(L,a,4); //尾插法建立链表
printf("头插法所得顺序为:");
DispList(L);
printf("链表的长度为:%d\n",ListLength(L));
printf("插入前链表的头节点地址:%d\n",L->next);
printf("插入前链表地址:%d\n",&L);
ListInsert(L,4,5); //在链表第四个元素前插入5
printf("插入一个元素后链表的元素为:");
DispList(L);
printf("插入后链表的头节点地址:%d\n",L->next);
printf("插入后链表地址:%d\n",&L);
}
使用引用时测试结果如下:
不使用引用时,测试结果如下:
可以看到在两次测试中链表都完成了中间插入的功能,只是在无引用时插入中的链表地址发送了改变。