如圖4.8所示,表中的各元素稱作“結點”。雙向鏈表的結點是結構體,由數據本體(這裏是整數key)、指向前一元素的指針prev以及指向後一元素的指針next組成。這些結構體通過指針連接成一個鏈,就形成了雙向鏈表。
program4.3 C++雙向鏈表的結點
strcut Node {
int key;
Node *prev, *next;
};
另外,在表頭設置一個特殊的結點可以簡化鏈表的實現。我們將這個結點稱爲“頭結點”。頭結點中雖然不包含實際數據,但他可以讓我們更輕鬆的對鏈表做更改。比如加入頭結點之後,我們將更容易實現刪除元素的操作。
init函數用於初始化鏈表。如圖4.9所示,它會生成一個NIL結點作爲鏈表的頭結點,然後讓prev和next都指向這個結點,從而創造一個空表。
program4.4 初始化雙向鏈表
Node *nil;
void init() {
nil = (Node *)malloc(sizeof(Node));
nil->next = nil;
nil->prev = nil;
}
頭結點是添加元素的起點。這裏的malloc是C語言標準庫中的函數,用於動態申請指定大小的空間。另外,“->”是通過指針變量訪問成員的運算符,稱爲箭頭運算符。
insert函數用於生成包含所輸入鍵值的結點,並將該結點添加到標的開頭。如圖4.10所示這個函數會以頭結點爲起點分四步改變指針所指的方向。
program4.5 往雙向表中插入元素
void insert(int key) {
Node *x = (Node *)malloc(sizeof(Node));
x->key = key;
//在頭結點後添加元素
x->next = nil->next;
nil->next->prev = x;
nil->next = x;
x->prev = nil;
}
listSearch函數用於搜索元素,它可以在鏈表中尋找包含指定鍵值的結點,並返回其指針。假設cur爲指向當前位置結點的指針,只要從頭結點的next所指的結點,即鏈表開頭的元素開始逐個執行cur = cur -> next,即可逐一訪問每個結點。
program4.6 在雙向鏈表中搜索元素
Node* listSearch(int key) {
Node *cur = nil->next; //從頭結點後面的元素開始訪問
while( cur != nil && cur->key != key) {
cur = cur->next;
}
retrun cur;
}
在訪問過程中發現key或者指針回到頭結點NIL時結束搜索,並返回此時cur的值。
deleteNode函數會通過如圖4.11所示的步驟改變指針所指的位置,從而刪除指定的結點t。在C++中,我們必須手動釋放已刪除結點的內存。這裏的free時C語言標準庫中的函數,用於釋放已不需要的內存空間。
program4.7 從雙向鏈表中刪除元素
void deleteNode(Node *t) {
if( t == nil ) return;
t->prev->next = t->next;
t->next->prev = t->prev;
free(t);
}
void deleteFirst() {
deleteNode( nil->next );
}
void deleteLast() {
deleteNode( nil->prev );
}
void deleteKey(int key) {
//刪除已搜索到的結點
deleteNode( listSearch(key));
}
例題;
代碼:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
struct Node {
int key;
Node *next,*prev;
};
Node *nil;
void init() { //初始化
nil = (Node *)malloc(sizeof(Node));
nil->next = nil;
nil->prev = nil;
}
Node* listSearch(int key) { //找出含有鍵值key的結點
Node *cur = nil->next;
while( cur != nil && cur->key != key) {
cur = cur->next;
}
return cur;
}
void insert(int key) { //在頭節點後插入某個元素
Node *x = (Node *)malloc(sizeof(Node));
x->key = key;
x->next = nil->next;
nil->next->prev = x;
nil->next = x;
x->prev = nil;
}
void deleteNode(Node *t) { //刪除結點 被下面調用函數 調用
if( t == nil) return;
t->prev->next = t->next;
t->next->prev = t->prev;
free(t); //釋放已經不需要的內存空間
}
void deleteFirst() { //刪除頭結點next所指向的結點
deleteNode(nil->next);
}
void deleteLast() { //刪除頭結點prev所指向的結點
deleteNode(nil->prev);
}
void deleteKey(int key) {
deleteNode(listSearch(key)); //刪掉搜索到的結點
}
void printList() { //打印鏈表
Node *cur = nil->next;
int isf = 0;
while(1) {
if( cur == nil ) break;
if(isf++ > 0) printf(" ");
printf("%d",cur->key);
cur = cur->next;
}
printf("\n");
}
int main()
{
int n,key,i;
char com[20];
cin>>n;
init();
int size = 0,np = 0,nd = 0;
for( i=0; i<n; i++ ) {
scanf("%s%d",com,&key);
if( com[0] == 'i') { insert(key); np++; size++;}
else if( com[0] == 'd') {
if( strlen(com) > 6) {
if( com[6] == 'F') deleteFirst();
else if( com[6] == 'L') deleteLast();
} else {
deleteKey(key); nd++;
}
size--;
}
}
printList();
return 0;
}
/*
7
insert 5
insert 2
insert 3
insert 1
delete 3
insert 6
delete 5
*/