赞
踩
(翻译文,稍加调整,加入了自己的解释)
相比SLL(singly linked list,单链表),DLL(Doubly Linked List,双链表)多了一个名为 previous pointer (Prev)的指针,该指针指向前一节点。SLL与DLL的相同点是都拥有需要存储的数据,和指向下一节点的指针。
C语言中DLL节点的表示:
/* Node of a doubly linked list */
struct Node {
int data;
struct Node* next; // Pointer to next node in DLL
struct Node* prev; // Pointer to previous node in DLL
};
双链表相对于单链表的优势:
1) DLL可以向前和向后遍历。
2)如果给出了要删除的节点的指针,则DLL中的删除操作会更有效。
3)我们可以在给定节点之前快速插入一个新节点。
在单链列表中,要删除节点,需要指向上一个节点的指针。为了获得该先前节点,有时会遍历列表。在DLL中,我们可以使用Prev指针获取先前的节点。
双链表相对于单链表的劣势:
1) DLL的每个节点都需要额外的空间才能存储Prev指针。
2)所有操作都需要一个额外的指针。例如,在插入过程中,我们需要同时修改Prev指针和Next指针。例如,在以下函数中,对于不同位置的插入,我们需要1到2个额外的步骤来设置Prev指针。
可以在四个位置添加节点:
1)在DLL的前端;
2)在给定节点之后;
3)在DLL的末尾;
4)在给定节点之前。
新节点总是添加到给定链接列表的首节点之前。新添加的节点成为DLL新的首节点。例如,如果给定的链表是10152025,我们在前面加了一个项5,那么链表就变成了510152025。我们把在列表前端添加节点的函数称为push(),push() 需要修改head指针,使head指针指向新的节点。
整个过程需要5个步骤:
/* Given a reference (pointer to pointer) to the head of a list and an int, inserts a new node on the front of the list. */ void push(struct Node** head_ref, int new_data) { /* 1. allocate node */ struct Node* new_node = (struct Node*)malloc(sizeof(struct Node)); /* 2. put in the data */ new_node->data = new_data; /* 3. Make next of new node as head and previous as NULL */ new_node->next = (*head_ref); new_node->prev = NULL; /* 4. change prev of head node to new node */ if ((*head_ref) != NULL) (*head_ref)->prev = new_node; /* 5. move the head to point to the new node */ (*head_ref) = new_node; }
以上5个步骤中的4个步骤与单链表的最前面插入步骤相同。唯一的额外步骤是多了第4步,更改原首节点的Prev指针,将指针从NULL指向新增节点。
步骤:
给定节点为next_node,新节点为new node,其数据为new_data。
1、检查next_node是否为NULL。如果为NULL,则从函数退出,因为在NULL之前不能添加任何新节点;
2、为新节点分配内存,将其称为new_node;
3、设置new_node-> data = new_data
4、将new_node的前一个指针指向next_node的前一个节点,new_node-> prev = next_node-> prev
5、将next_node的前一个指针设置为new_node,next_node-> prev = new_node。在图例中,就是将C节点的prev指针,从指向A节点改为指向B节点。
6、将此new_node的下一个指针设置为next_node,new_node-> next = next_node;
7、如果new_node的前一个节点不为NULL,则将此前一个节点的下一个指针设置为new_node,new_node-> prev-> next = new_node。在图例中,就是修改A节点的next指针,从C指向B。
8、否则,如果new_node的prev为NULL,它将是新的头节点。因此,使(* head_ref)= new_node。
新节点总是添加到给定链表的最后一个节点之后。例如,如果给定的DLL是510152025,而我们在末尾添加了第30个项目,则DLL变为51015202530。
共7步:
/* Given a reference (pointer to pointer) to the head of a DLL and an int, appends a new node at the end */ void append(struct Node** head_ref, int new_data) { /* 1. allocate node */ struct Node* new_node = (struct Node*)malloc(sizeof(struct Node)); struct Node* last = *head_ref; /* used in step 5*/ /* 2. put in the data */ new_node->data = new_data; /* 3. This new node is going to be the last node, so make next of it as NULL*/ new_node->next = NULL; /* 4. If the Linked List is empty, then make the new node as head */ if (*head_ref == NULL) { new_node->prev = NULL; *head_ref = new_node; return; } /* 5. Else traverse till the last node */ while (last->next != NULL) last = last->next; /* 6. Change the next of last node */ last->next = new_node; /* 7. Make last node as previous of new node */ new_node->prev = last; return; }
因为链表通常是由它的head来表示的,所以我们必须遍历列表直到结束,然后将最后一个节点的下一个更改为新节点。第1步创建的last指针用于遍历链表,指向原链表的最后一个节点;第6步修改原链表最后一个节点的next指针,将指向NULL修改为指向新节点;第7步配置新节点的prev指针,为原链表的最后节点。
共7步:
/* Given a node as prev_node, insert a new node after the given node */ void insertAfter(struct Node* prev_node, int new_data) { /*1. check if the given prev_node is NULL */ if (prev_node == NULL) { printf("the given previous node cannot be NULL"); return; } /* 2. allocate new node */ struct Node* new_node = (struct Node*)malloc(sizeof(struct Node)); /* 3. put in the data */ new_node->data = new_data; /* 4. Make next of new node as next of prev_node */ new_node->next = prev_node->next; /* 5. Make the next of prev_node as new_node */ prev_node->next = new_node; /* 6. Make prev_node as previous of new_node */ new_node->prev = prev_node; /* 7. Change previous of new_node's next node */ if (new_node->next != NULL) new_node->next->prev = new_node; }
在图例中,new_node为E节点,prev_node为B节点。第4步将E节点的next指针指向C节点;第5步将B节点的next指针指向从C节点改为E节点;第6步将E节点prev指针指向B节点;第7步将C节点prev指针指向从B节点改为E节点。
以下是上述方法的实现:
// A complete working C program to demonstrate all // insertion before a given node #include <stdio.h> #include <stdlib.h> // A linked list node struct Node { int data; struct Node* next; struct Node* prev; }; /* Given a reference (pointer to pointer) to the head of a list and an int, inserts a new node on the front of the list. */ void push(struct Node** head_ref, int new_data) { struct Node* new_node = (struct Node*)malloc(sizeof(struct Node)); new_node->data = new_data; new_node->next = (*head_ref); new_node->prev = NULL; if ((*head_ref) != NULL) (*head_ref)->prev = new_node; (*head_ref) = new_node; } /* Given a node as next_node, insert a new node before the given node */ void insertBefore(struct Node** head_ref, struct Node* next_node, int new_data) { /*1. check if the given next_node is NULL */ if (next_node == NULL) { printf("the given next node cannot be NULL"); return; } /* 2. allocate new node */ struct Node* new_node = (struct Node*)malloc(sizeof(struct Node)); /* 3. put in the data */ new_node->data = new_data; /* 4. Make prev of new node as prev of next_node */ new_node->prev = next_node->prev; /* 5. Make the prev of next_node as new_node */ next_node->prev = new_node; /* 6. Make next_node as next of new_node */ new_node->next = next_node; /* 7. Change next of new_node's previous node */ if (new_node->prev != NULL) new_node->prev->next = new_node; /* 8. If the prev of new_node is NULL, it will be the new head node */ else (*head_ref) = new_node; } // This function prints contents of linked list starting from the given node void printList(struct Node* node) { struct Node* last; printf("\nTraversal in forward direction \n"); while (node != NULL) { printf(" %d ", node->data); last = node; node = node->next; } printf("\nTraversal in reverse direction \n"); while (last != NULL) { printf(" %d ", last->data); last = last->prev; } } /* Driver program to test above functions*/ int main() { /* Start with the empty list */ struct Node* head = NULL; push(&head, 7); push(&head, 1); push(&head, 4); // Insert 8, before 1. So linked list becomes 4->8->1->7->NULL insertBefore(&head, head->next, 8); printf("Created DLL is: "); printList(head); getchar(); return 0; }
输出结果为:
Created DLL is:
Traversal in forward direction
4 8 1 7
Traversal in reverse direction
7 1 8 4
[1] jatinreaper, 29AjayKumar, Murali Krishna Marimekala, rathbhupendra, Akanksha_Rai.Doubly Linked List | Set 1 (Introduction and Insertion)[EB/OL].https://www.geeksforgeeks.org/doubly-linked-list/,2020-01-01.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。