源碼:https://github.com/cjy513203427/C_Program_Base/tree/master/54.%E9%93%BE%E8%A1%A8
需要實現的方法
#pragma once #include"Node.h" #ifndef LIST_H #define LIST_H #include<iostream> using namespace std; class List { public: List();//構造函數 ~List();//析構函數 void ClearList();//清空鏈表 bool ListEmpty();//鏈表判空 int ListLength();//鏈表長度 bool GetElem(int i, Node *pNode);//獲取指定索引的元素 int LocateElem(Node *pNode);//獲取指定元素的索引 bool PriorElem(Node *pCurrentNode, Node *pPreNode);//獲取前驅結點 bool NextElem(Node *pCurrentNode, Node *pNextNode);//獲取后繼結點 void ListTraverse();//遍歷 bool ListInsert(int i,Node *pNode);//插入元素 bool ListDelete(int i, Node *pNode);//刪除元素 bool ListInsertHead(Node *pNode);//插入在頭結點后面 bool ListInsertTail(Node *pNode);//插入到鏈表最后 private: Node * m_pList; int m_iLength; }; #endif // !LIST_H
1.構造函數
堆中為頭結點m_pList申請內存
m_pList數據域置為0
指向地址為空,事實上這里聲明了一個頭結點,頭結點沒有后繼結點並且數據域為空
長度置為0

List::List() { m_pList = new Node; m_pList->data = 0; m_pList->next = NULL; m_iLength = 0; }
2.析構函數
調用清空鏈表方法
刪除頭結點並置空
List::~List() { ClearList(); delete m_pList; m_pList = NULL; }
3.清空鏈表
聲明一個Node*類型的指針指向m_pList的下一個結點,特別指明:m_pList是頭結點,m_pList->next是頭結點的指針域
判斷currentNode是否為空,即判斷m_pList的指針域是否為空,為空說明currentNode是尾結點,尾結點沒有后繼結點
currentNode不為空時,聲明一個Node*類型的指針temp指向currentNode的下一個結點,也可以理解為temp接收currentNode的指針域值
刪除當前的currentNode,再把temp保存的currentNode的指針域賦值回去
依次類推...
循環結束,再把尾結點指針域置空

清空鏈表和析構函數的區別:清空鏈表是將頭結點之后的結點全部清空,析構函數是把頭結點和之后的結點全部清空
void List::ClearList() { Node *currentNode = m_pList->next; while (currentNode != NULL) { Node *temp = currentNode->next; delete currentNode; currentNode = temp; } m_pList->next = NULL; }
4.鏈表判空與獲取長度
沒什么好說的
bool List::ListEmpty() { return 0 == m_iLength ? true : false; } int List::ListLength() { return m_iLength; }
5.在頭結點后面插入元素
pNode指針作為參數傳入
temp保存頭結點的指針域,指向第一個結點
在堆中申請一個newNode指針的內存
沒申請到內存返回錯誤
申請到內存,參數的數據域賦值給新結點數據域
頭結點指向新結點
新結點指向原來頭結點的下一個結點,這樣鏈表就連接起來了

bool List::ListInsertHead(Node *pNode) { Node *temp = m_pList->next; Node *newNode = new Node; if (newNode == NULL) //判斷申請的結點內存是否為空 { return false; } else { newNode->data = pNode->data; m_pList->next = newNode; newNode->next = temp; m_iLength++; return true; } }
6.在尾結點后面插入元素
pNode指針作為參數傳入
currentNode接收頭結點
判斷currentNode是否是尾結點,因為尾結點后繼結點為空
循環到最后一個結點,此時currentNode->next=NULL
在堆中申請一個newNode的內存
沒申請到內存返回錯誤
申請到內存
pNode的數據域賦值給newNode的數據域
新結點指針域置空
currentNode指向新結點
新結點指向空,這樣鏈表就連接起來了,新結點成為了新的尾結點
鏈表長度++
返回正確

bool List::ListInsertTail(Node *pNode) { Node *currentNode = m_pList; while (currentNode->next != NULL) { currentNode = currentNode->next; } Node *newNode = new Node; if (newNode == NULL) { return false; } else { newNode->data = pNode->data; newNode->next = NULL; currentNode->next = newNode; m_iLength++; return true; } }
7.插入元素
判斷參數i的合法性
i不能小於0,i不能大於鏈表長度,i等於鏈表長度代表可以尾元素后插入
currentNode保存頭結點
聲明newNode
pNode數據域賦值給newNode數據域
新結點指向原來結點的下一個結點
原來的結點指向新結點

bool List::ListInsert(int i, Node *pNode) { if (i<0 || i>m_iLength) { return false; } Node *currentNode = m_pList; for (int k = 0; k < i; k++) { currentNode = currentNode->next; } Node *newNode = new Node; if (newNode == NULL) //判斷申請的結點內存是否為空 { return false; } else { newNode->data = pNode->data; newNode->next = currentNode->next; currentNode->next = newNode; return true; } }
8.刪除元素
判斷i是否合法,索引最大是m_iLength-1,和循環條件k<i對應
currentNode保存頭指針
currentNodeBefore置空
currentNodeBefore指向currentNode的下一個結點的指針域,這樣currentNode就可以被刪除釋放了
pNode數據域接收當前結點的數據域
刪除當前結點並置空

bool List::ListDelete(int i, Node *pNode) { if (i<0 || i>=m_iLength) { return false; } Node *currentNode = m_pList; Node *currentNodeBefore = NULL; for (int k = 0; k <= i; k++) { currentNodeBefore = currentNode; currentNode = currentNode->next; } currentNodeBefore->next = currentNode->next; pNode->data = currentNode->data; delete currentNode; currentNode = NULL; m_iLength--; return true; }
9.獲取指定索引的元素
邏輯同刪除元素
bool List::GetElem(int i, Node *pNode) { if (i<0 || i >= m_iLength) { return false; } Node *currentNode = m_pList; Node *currentNodeBefore = NULL; for (int k = 0; k <= i; k++) { currentNodeBefore = currentNode; currentNode = currentNode->next; } pNode->data = currentNode->data; return true; }
10.獲取指定元素的索引
currenNode保存頭指針
只要currentNode的指針域/指向不為空,繼續下去
如果參數的數據域等於currentNode的數據域,返回count,count就是索引
int List::LocateElem(Node *pNode) { Node *currentNode = m_pList; int count = 0; while (currentNode->next != NULL) { currentNode = currentNode->next; if (currentNode->data == pNode->data) { return count; } count++; } return -1; }
11.獲取前驅結點
currentNode保存頭結點
中間變量tempNode置空
currentNode指針域不為空開始循環
tempNode保存當前結點
currentNode像后移一位
如果pCurrentNode的數據域等於當前結點的數據域
如果tempNode等於頭結點,返回錯誤
將tempNode的數據域賦值給pPreNode的數據域,此時tempNode是保存的currentNode,currentNode是下一個的結點
所以currentNode->data==pCurrentNode->data是currentNode下一個結點的數據域和pCurrentNode比較
bool List::PriorElem(Node *pCurrentNode, Node *pPreNode) { Node *currentNode = m_pList; Node *tempNode = NULL; int count = 0; while (currentNode->next != NULL) { tempNode = currentNode; currentNode = currentNode->next; if (currentNode->data == pCurrentNode->data) { if (tempNode == m_pList) { return false; } pPreNode->data = tempNode->data; return true; } } return false; }
12.獲取后繼結點
currentNode保存頭指針
currentNode指針域不為空執行循環
currentNode一直向后移動
如果pCurrentNode的數據域等於currentNode的數據域
如果是尾結點,返回錯誤
再將當前結點指向的下一個結點的數據域賦值給pNextNode的數據域
bool List::NextElem(Node *pCurrentNode, Node *pNextNode) { Node *currentNode = m_pList; while (currentNode->next != NULL) { currentNode = currentNode->next; if (currentNode->data == pCurrentNode->data) { if (currentNode->next == NULL) { return false; } pNextNode->data = currentNode->next->data; return true; } } }
13.遍歷
currentNode保存頭指針
currentNode只要不是尾結點一直遍歷下去
currentNode后移,調用printNode()方法
void List::ListTraverse() { Node *currentNode = m_pList; while (currentNode->next != NULL) { currentNode = currentNode->next; currentNode->printNode(); } }
