为什么需要双指针来更改头部,而无需更改链接列表中的其他位置

时间:2019-03-28 16:36:04

标签: c++

void insertAtTop(node** head, int value){
    node* temp=new node();
    temp->data=value;
    temp->next=*head;
    *head=temp;
}

void insertAtLast(node*head, int value){
    while(head->next!=NULL){
        head=head->next;
    }
    node*temp=new node();
    temp->data=value;
    temp->next=NULL;
    head->next=temp;
}

我不明白为什么您需要使用指针来更改头部,但是如果您想在其他地方添加元素,则只需发送node* head而不是{{1} }。就像node** head insertatLast一样,因为论点有效,但是如果我对node*head做同样的事情,那不会。

4 个答案:

答案 0 :(得分:1)

同时使用insertAtTopinsertAtLast可以同时实现pass by referencepass by value。我建议您阅读difference between pass by reference and pass by value。您还可以阅读this

我假设head被声明为node* head;

通过引用传递:

void insertAtTop(node** head, int value){
    node* temp=new node();
    temp->data=value;
    temp->next=*head;
    *head=temp;
}

致电:insertAtTop(&head, value);

void insertAtLast(node** head, int value){
    node* h = *head;
    while(h->next!=NULL){
        h = h->next;
    }
    node* new_node=new node();
    new_node->data=value;
    new_node->next=NULL;
    h->next=new_node;
}

致电:insertAtLast(&head, value);

按值传递:

node* insertAtTop(node* head, int value){
    node* temp=new node();
    temp->data=value;
    temp->next= head;
    head = temp;
    return head;
}

致电:head = insertAtTop(head, value);

node* insertAtLast(node* head, int value){
    node* original_head = head;
    while(head->next!=NULL){
        head=head->next;
    }
    node*temp=new node();
    temp->data=value;
    temp->next=NULL;
    head->next=temp;
    return original_head;
}

致电:head = insertAtLast(head, value);

答案 1 :(得分:0)

您不必使用双指针。请参见下面的代码:

node* front(int n, node* head)
{
    node *tmp = new node;
    tmp -> data = n;
    tmp -> next = head;
    head = tmp;
    return head;
}

答案 2 :(得分:0)

使用双指针,您可以将指针传递给指针。当您只有一个指针时,对其取消引用将为您提供变量的值。使用双指针,解引用可为您提供变量在内存中的地址。将节点添加到列表的最前面时,您将使用已经为头节点创建的节点,并传递指向它的指针的地址。而要添加到链表头的原因是必须这样做的原因是,由于链表结构被定义为具有最初指向null的头节点,因此您已经在内存中某个位置引用了链表的头。以及列表顶部的后续添加项将更改查找该链接列表开始位置的位置。

答案 3 :(得分:0)

两者中都有一个双指针。从这两个函数来看这两行:

*head=temp;  // from insertAtTop

head->next=temp; // from insertAtLast

请注意,head->next = temp可以等效地写为(*head).next = temp

那里有一个“双指针”:head是指向结构的指针,并且该结构包含指针next。基本上这两个图片:

*head = temp的图表:

head --> [ *--]---> old_head
            ^
            `-- temp is stored here, replacing the old_head

head->next = temp(*head).next = temp的图表。出于示例的目的,节点结构被表示为三个存储单元,其中第三个是next字段。确切的内存详细信息取决于您的编译器以及如何定义结构!

head  --> [    ]
          [    ] 
          [ *--]--> old_next
             ^
             `-- temp is stored here, replacing old_next

基本上,唯一的区别是您拥有一个结构而不是一个指针对象。

在两种情况下,都将更新指针以引用新插入的节点。在insertAtTop情况下,我们必须替换代表列表本身的那个指针。我们将列表对象表示为指向第一个节点的指针。如果列表已更改,使其具有不同的第一个节点,则该指针必须更改。在列表中的其他位置插入时,我们必须更新前一个节点的next指针以指向新节点,因此我们将其分配给(*head).next

我们可以重写insertAtLast以将insertAtTop用作子例程:

node* insertAtLast(node* head, int value){
    /* find the insertion point */
    node* original_head = head;
    while(head->next!=NULL){
        head=head->next;
    }
    /* now treat that as the head */
    (void) insertAtTop(&head->next, value);
    return original_head;
}

如果您跟踪对insertAtHead的调用中发生了什么,您会发现它与我们替换的代码完全相同。我们取出了这段代码:

    node* new_node=new node();
    new_node->data=value;
    new_node->next=NULL;
    h->next=new_node;

但这与insertAtHead的正文几乎相同:

   node* temp=new node();
   temp->data=value;
   temp->next=*head;
   *head=temp;

我们将表达式&h->next的值作为head参数传递。因此temp->next = *head实际上是temp->next = *&h->next,其中*&被抵消,剩下temp->next = h->next。但是我们知道h->nextNULL:我们的while循环确保了这一点。因此,这实际上是temp->next = NULL。 当然,*head = temp*(&h->next) = temph->next = temp一样。