观察和发现,为什么...
我决定做一些实验并得出一些结论,
观察 1- 如果链表不为空,那么我们可以仅使用单个指针将节点添加到其中(显然是在末尾)。
int insert(struct LinkedList *root, int item){
struct LinkedList *temp = (struct LinkedList*)malloc(sizeof(struct LinkedList));
temp->data=item;
temp->next=NULL;
struct LinkedList *p = root;
while(p->next!=NULL){
p=p->next;
}
p->next=temp;
return 0;
}
int main(){
int m;
struct LinkedList *A=(struct LinkedList*)malloc(sizeof(struct LinkedList));
//now we want to add one element to the list so that the list becomes non-empty
A->data=5;
A->next=NULL;
cout<<"enter the element to be inserted\n"; cin>>m;
insert(A,m);
return 0;
}
解释起来很简单(基本)。我们的 main 函数中有一个指针,它指向列表的第一个节点(根)。在insert() 函数中,我们传递根节点的地址,并使用该地址到达列表的末尾并向其添加一个节点。因此我们可以得出结论,如果我们在函数(不是主函数)中有变量的地址,我们可以从该函数中永久更改该变量的值,这将反映在主函数中。
OBSERVATION 2-上述添加节点的方法在列表为空时失败。
int insert(struct LinkedList *root, int item){
struct LinkedList *temp = (struct LinkedList*)malloc(sizeof(struct LinkedList));
temp->data=item;
temp->next=NULL;
struct LinkedList *p=root;
if(p==NULL){
p=temp;
}
else{
while(p->next!=NULL){
p=p->next;
}
p->next=temp;
}
return 0;
}
int main(){
int m;
struct LinkedList *A=NULL; //initialise the list to be empty
cout<<"enter the element to be inserted\n";
cin>>m;
insert(A,m);
return 0;
}
如果你继续添加元素并最终显示列表,那么你会发现列表没有发生任何变化,仍然是空的。
我想到的问题是,在这种情况下,我们也传递了根节点的地址,那么为什么修改没有发生,因为永久修改和主函数中的列表没有变化。为什么?为什么?为什么?
然后我观察到一件事,当我写A=NULL 时,A 的地址变为0。这意味着现在A 没有指向内存中的任何位置。所以我删除了A=NULL;这一行,并在插入函数中做了一些修改。
一些修改,(下面insert()函数只能将一个元素添加到一个空列表中,只是为了测试目的而写了这个函数)
int insert(struct LinkedList *root, int item){
root= (struct LinkedList *)malloc(sizeof(struct LinkedList));
root->data=item;
root->next=NULL;
return 0;
}
int main(){
int m;
struct LinkedList *A;
cout<<"enter the element to be inserted\n";
cin>>m;
insert(A,m);
return 0;
}
上述方法也失败了,因为在insert() 函数中,根存储与main() 函数中的A 相同的地址,但在root= (struct LinkedList *)malloc(sizeof(struct LinkedList)); 行之后,存储在root 中的地址发生了变化。因此,现在root(在insert()函数中)和A(在main()函数中)存储不同的地址。
所以正确的最终程序应该是,
int insert(struct LinkedList *root, int item){
root->data=item;
root->next=NULL;
return 0;
}
int main(){
int m;
struct LinkedList *A = (struct LinkedList *)malloc(sizeof(struct LinkedList));
cout<<"enter the element to be inserted\n";
cin>>m;
insert(A,m);
return 0;
}
但是我们不想要两种不同的插入函数,一种是当列表为空时,另一种是当列表不为空时。现在来了双指针,这让事情变得简单。
我注意到重要的一件事是指针存储地址
当与 '*' 一起使用时,它们在该地址给出值,但指针
他们有自己的地址。
现在是完整的程序,稍后解释概念。
int insert(struct LinkedList **root,int item){
if(*root==NULL){
(*root)=(struct LinkedList *)malloc(sizeof(struct LinkedList));
(*root)->data=item;
(*root)->next=NULL;
}
else{
struct LinkedList *temp=(struct LinkedList *)malloc(sizeof(struct LinkedList));
temp->data=item;
temp->next=NULL;
struct LinkedList *p;
p=*root;
while(p->next!=NULL){
p=p->next;
}
p->next=temp;
}
return 0;
}
int main(){
int n,m;
struct LinkedList *A=NULL;
cout<<"enter the no of elements to be inserted\n";
cin>>n;
while(n--){
cin>>m;
insert(&A,m);
}
display(A);
return 0;
}
以下是观察结果,
1. root存储指针A的地址(&A),*root存储指针A存储的地址,**root存储A存储地址的值。用简单的语言root=&A、*root= A 和**root= *A。
2.如果我们写*root= 1528,那么这意味着存储在root中的地址的值变为1528,因为存储在root中的地址是指针A的地址(&A)因此现在A=1528(即存储在A 中的地址为1528)并且此更改是永久性的。
每当我们更改*root 的值时,我们确实在更改存储在root 中的地址的值,并且由于root=&A(指针A 的地址)我们间接更改A 的值或存储在A.
所以现在如果A=NULL(列表为空)*root=NULL,那么我们创建第一个节点并将其地址存储在*root,即间接我们将第一个节点的地址存储在A。如果 list 不为空,则一切都与之前使用单指针的函数相同,只是我们将 root 更改为 *root,因为存储在 root 中的内容现在存储在 *root 中。