這篇“C++怎么實現雙向鏈表”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“C++怎么實現雙向鏈表”文章吧。
前面文章分析了單向鏈表,并給出了python和C++實現:單鏈表從原理到實現,python和C++兩個版本
本文介紹的雙向鏈表是在單向鏈表基礎上的一個改進,每個節點指向其直接前驅和直接后繼節點。因此,從雙向鏈表的任意位置開始,都能訪問所有的節點。
雙向鏈表的缺點:
從節點的結構上可以看出,雙向鏈表的所需的存儲空間大于單向鏈表。同時,對于插入和刪除等操作來說,雙向鏈表的節點操作更加復雜,涉及到節點的前后兩個節點。
雙向鏈表的節點:
對于雙向鏈表來說,它的每個節點要指向“直接前驅”和“直接后繼”,所以節點類需要含有兩個指針域。指向直接前驅的指針使用pre表示,指向后繼的指針使用next表示。

雙向鏈表的節點含有兩個指針域,即直接前驅pre和直接后繼next。節點類采用的是模板實現,這樣其所存儲的數據就不再依賴于特定類型。
template<class T>
class Node {
public:
Node() {}
Node *pre;
Node *next;
// 由于data屬性是私有的
// 所以采用get和set對data進行處理
void setData(T data) { this->data = data; }
T getData() { return this->data; }
private:
T data;
};鏈表類應該包含基本的增、改、刪、查等操作,由于其各種功能的實現是很相似的,
所以下面給出了需要實現的典型函數:
構造函數:
isEmpty()判斷是否為空;
size()返回鏈表長度;
insert()頭插、尾插、中間插入節點;
delete()刪除節點;
getNode()獲取節點;
traversal()遍歷鏈表;
鏈表類的定義如下:
template<class P>
class DoubleLinkedList {
public:
DoubleLinkedList();
bool isEmpty();
Node<P> *getNode(int index);
int size();
void insert(int data, int index);
void traversal();
void remove(int index);
private:
Node<P> *head;
};初始化時需要創建頭節點,作為頭指針:
template<class P>
DoubleLinkedList<P>::DoubleLinkedList() {
// 創建頭結點
head = new Node<P>();
head->pre = NULL;
head->next = NULL;
head->setData(666);
}對于雙向鏈表來說,判斷是否為空只需要判斷頭指針是否指向其他Node節點:
template<class P>
bool DoubleLinkedList<P>::isEmpty() {
if (head->next == NULL) {
return true;
}
else
{
return false;
}
}獲取鏈表長度時需要判斷鏈表是否為空,從而確定是否采用遍歷的方式計算鏈表的長度。
由于采用的不是循環鏈表,所以循環的結束條件是判斷是否指向空節點:
template<class P>
int DoubleLinkedList<P>::size() {
if (isEmpty()) {
return 0;
}
else {
int count = 0;
Node<P> *current = head->next;
// 循環結束條件
while (current!=NULL)
{
current = current->next;
count++;
}
return count;
}
}在插入和刪除等操作中,需要頻繁的進行節點獲取操作。
所以應該封裝為單獨的函數用于節點獲取,如下:
template<class P>
Node<P> *DoubleLinkedList<P>::getNode(int index) {
Node<P> *current = head;
int currentCount = 0;
// 循環結束條件
while (currentCount<=index)
{
current = current->next;
currentCount++;
}
return current;
}插入節點依舊包含頭插法,尾插法和任意位置的插入。插入操作與單向鏈表的最大區別在于節點的指針移動較為復雜,需要將插入位置前后兩個節點與新節點均建立聯系:
template<class P>
void DoubleLinkedList<P>::insert(int data, int index) {
Node<P> *node = new Node<P>();
node->setData(data);
// 1、列表為空時
if (isEmpty()) {
head->next = node;
node->pre = head;
return;
}
// 2、頭插法
if (index == 0) {
node->next = head->next;
head->next->pre = node;
node->pre = head;
head->next = node;
}
// 3、尾插法
else if (index >= this->size() - 1) {
// printf("index %d, size %d \n", index, this->size());
Node<P> *temp = this->getNode(this->size()-1);
temp->next = node;
node->pre = temp;
}
// 4、任意位置插入
else
{
Node<P> *pre = this->getNode(index);
Node<P> *next = pre->next;
node->next = pre->next;
node->pre = pre;
pre->next = node;
node->next->pre = node;
}
}前面已經定義了用于獲取節點的getNode()函數,所以remove()函數只需要進行指針移動操作。
將所要刪除的節點的直接前驅節點和直接后繼節點相連:
template<class P>
void DoubleLinkedList<P>::remove(int index) {
// 保證索引有意義
if ((index < (this->size()-1)) && (index>0)) {
Node<P> *node = this->getNode(index);
Node<P> *pre = node->pre;
Node<P> *next = node->next;
pre->next = next;
next->pre = pre;
}
}雖然可以從雙向鏈表的任一個節點開始遍歷整個鏈表,但是下面的實現依舊是從頭結點開始的,循環的結束依舊是指向空指針:
template<class P>
void DoubleLinkedList<P>::traversal() {
if (!isEmpty()) {
Node<P> *current = head;
while (current)
{
cout << current->getData() << endl;
current = current->next;
}
}
}以上就是關于“C++怎么實現雙向鏈表”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。