單鏈表 C++ 實現 - 含虛擬頭節點
阿新 • • 發佈:2018-10-29
:link 和數 std inpu amp move brush 第一個 pre
本文例程下載鏈接:
鏈表 vs 數組
鏈表和數組的最大區別在於鏈表不支持隨機訪問,不能像數組那樣對任意一個(索引)位置的元素進行訪問,而需要從頭節點開始,一個一個往後訪問直到查找到目標位置。
單鏈表
與順序表相對,鏈表是一種鏈式存儲方式。單鏈表是實現順序表最簡單的一種鏈表,根據是否包含虛擬頭節點,分為含虛擬頭節點和不含虛擬頭節點兩種方式。本文以含虛擬頭節點為例,用C++實現單鏈表數據結構ADT。
節點:鏈表的組成元素,每個節點包含數據域data和指針域next。例程為了簡化設計,data用int類型表示。
虛擬頭節點:鏈表的第一個節點,為了維護鏈表操作方便,但不存放數據。
單鏈表結構設計
含虛擬頭節點的單鏈表list如下圖所示,包含一個虛擬頭節點V0,而V1~Vn通過前驅節點next域進行鏈接,從而形成一個單向鏈式結構。
虛擬頭節點V0,不包含數據;V1~Vn包含數據,Vn->next = NULL
名稱 | 描述 | 代表自定義符號 |
虛擬頭節點 | 不包含數據 | Vh/head |
尾節點 | 鏈表的最後一個節點,特征:next=NULL | Vn-1/tail |
普通數據節點 | 包含具有實際意義數據的節點 | V0~Vn-1 |
長度 | 包含實際意義數據節點數為n(不包括Vh) | length |
空鏈表 | 虛擬頭節點為空,即head=NULL | V0=NULL |
位置 |
從V0開始(Vh後繼節點)開始計數0,直到Vn-1(尾節點)的節點對應位置。範圍[0,n-1] |
position |
插入節點 | 在指定位置處插入節點,除插入節點及前驅和後繼,不改變鏈表其他節點關系 | insert |
刪除節點 | 在指定位置處刪除節點, 除插入節點及前驅和後繼,不改變鏈表其他節點關系 | remove |
單鏈表ADT設計
1. 鏈表節點ADT Node.h
/** * 單鏈表節點類 */ class Node { int data; Node *next; public: Node(); Node(Node*, int); };
2. 單鏈表ADT LinkedList.h
/** * 單鏈表類 * @description 帶虛擬頭節點 */ class LinkedList { private: Node *head; Node *tail; public: LinkedList(); virtual ~LinkedList(); Status Init(); // 初始化鏈表 Status Destroy(); // 銷毀鏈表 int Length(); // 求鏈表長度(有效節點)節點個數 bool IsEmpty(); // 鏈表是否為空 Status Insert(int pos, int value); // 在指定位置生產節點, 並插入數據 Status Remove(int pos); // 刪除指定位置節點 int GetValue(int pos); // 讀取指定位置節點數據 Node* GetAddress(int pos); // 獲取知道位置節點的地址 int SearchPosition(int value); // 搜索第一個出現的元素值的節點位置 Status Update(int pos, int value); // 更新指定位置節點數據 Status ClearList(); // 清除鏈表數據(不包含頭節點) Status PrintList(); // 順序打印鏈表節點數據 Status Reverse(); // 反轉鏈表 };
3. Node實現 Node.cpp
#include "Node.h" #include <cstdlib> Node::Node() { data = 0; next = NULL; } Node::Node(Node* newNext, int newValue) { data = newValue; next = newNext; } Node::~Node() { // TODO Auto-generated destructor stub }
4. 鏈表實現LinkedList.cpp
#include "LinkedList.h" #include <cstdlib> #include <iostream> using namespace std; LinkedList::LinkedList() { head = NULL; tail = NULL; } LinkedList::~LinkedList() { Destroy(); } /** * 初始化鏈表 */ Status LinkedList::Init() { // 創建虛擬頭節點 head = new Node(NULL, 0); if(head != NULL) { return OK; } return ERROR; } /** * 銷毀鏈表 * @description 與初始化操作相對, 刪除所有鏈表節點, 包括頭節點 */ Status LinkedList::Destroy() { if(head) { Node *curP = head; while(head) { curP = head->next; delete head; head = curP; } return OK; } else { cout <<"The list is NULL"<<endl; return ERROR; } } /** * 求鏈表長度(有效節點)節點個數 * @description 從虛擬頭節點的下一個節點開始計算有效節點數 */ int LinkedList::Length() { if(!head) { cout <<"The list is NULL"<<endl; exit(-1); } Node *curP = head->next; int n = 0; while(curP != NULL) { n ++; curP = curP->next; } return n; } /** * 判斷鏈表是否為空 * @description 判斷依據: 虛擬頭節點head == NULL * 註: 長度為0 不代表鏈表為空 */ bool LinkedList::IsEmpty() { return (head == NULL); } /** * 在指定位置生產節點, 並插入數據 * @param pos [in] 待插入位置. 從頭節點的後繼開始為0計數,所需要經過的節點數。範圍:0~n-1 * @param value [in] 待插入節點數據域 */ Status LinkedList::Insert(int pos, int value) { if(IsEmpty()) { cout <<"The list is NULL. Pls Create an List and init it first."<<endl; exit(-1); } // create a new Node Node *newNode = new Node(NULL, value); if(pos == 0) { newNode->next = head->next; head->next = newNode; } else if(pos >0 && pos <= Length()) { // find the predecessor node to be inserted Node *p = GetAddress(pos-1); // insert the new Node to List if(p != NULL) { if(p->next != NULL) {// not tail newNode->next = p->next; } p->next = newNode; } } else { cout<<"Error: Input param Pos is illegal(<0)"<<endl; return ERROR; } return OK; } /** * 刪除指定位置節點 * @param pos [in] 待插入位置. pos有效範圍: [0, n), 0代表虛擬節點後面一個節點, 虛擬節點無法通過此API刪除 * */ Status LinkedList::Remove(int pos) { // find the prior node Node *curP = GetAddress(pos); if(curP == NULL) { return ERROR; } // get the node to be delete Node *tmp = curP->next; // delete the node if(tmp != NULL) {// not NULL node if(tmp->next != NULL) {// not tail curP->next = tmp->next; tmp->next = NULL; } else { curP->next = NULL; delete tmp; } } return OK; } /** * 讀取指定位置節點數據 */ int LinkedList::GetValue(int pos) { // find the node Node *curP = GetAddress(pos); if(curP != NULL) { return curP->data; } else { return 0; } } /** * 獲取位置節點的地址 * @param pos [in] 從頭節點的後繼開始為0計數,所需要經過的節點數。範圍:[0, n-1], n是鏈表長度(有效數據節點數) * @return 節點的地址 */ Node* LinkedList::GetAddress(int pos) { // valid list is null or not if(!head) { cout <<"The list is NULL"<<endl; exit(-1); } // valid intput param if(pos < 0 || pos >= Length()) { cout <<"Insert position is out of the list‘s bounds"<<endl; exit(-1); } // 順序查找位置pos的節點 int i = 0; Node *curP = head->next; while(curP != NULL) { if(i == pos) { return curP; } i ++; curP = head->next; } return NULL; } /** * 搜索第一個出現的元素值的節點位置 * @param value 待查找值 * @return 鏈表第一個節點的數據域=value的位置 * - ERROR 錯誤 * - >=0 位置序號 */ int LinkedList::SearchPosition(int value) { // valid list is null or not if(!head) { cout <<"The list is NULL"<<endl; exit(-1); } // sequential search Node *p = head->next; int i = 0; while(p != NULL) { i ++; if(p->data == value) return i; else p = p->next; } cout<< "Can‘t find the value in list"<<endl; return ERROR; } /** * 更新指定位置節點數據 * @param pos [in] 待更新節點位置 * @param value [in] 待更新節點要修改的目標值 * @return 更新結果 * - OK 正常更新 * - ERROR 沒有找到待更新節點, 可能由位置錯誤或者鏈表為空導致 */ Status LinkedList::Update(int pos, int value) { // find the node Node *curP = GetAddress(pos); if(curP != NULL) { curP->data = value; return OK; } return ERROR; } /** * 清除鏈表數據(不包含頭節點) */ Status LinkedList::ClearList() { // valid list is null or not if(!head) { cout <<"The list is NULL"<<endl; exit(-1); } Node *p = head->next; Node *tmp = NULL; while(p!=NULL) { tmp = p; p = p->next; delete tmp; } head->next = NULL; return OK; } /** * 順序打印鏈表節點數據 */ Status LinkedList::PrintList() { // valid list is null or not if(IsEmpty()) { cout <<"The list is NULL. Pls Create an List and init it first."<<endl; return ERROR; } cout <<"List:[ "; if(Length() == 0) { cout<<"NULL"; } else { Node *p = head->next; while(p != NULL) { cout<<p->data<<" "; p = p->next; } } cout <<"] "<<endl; return OK; } /** * 反轉鏈表, 除虛擬頭節點 */ Status LinkedList::ReverseList() { // valid list is null or not if(IsEmpty()) { cout <<"The list is NULL. Pls Create an List and init it first."<<endl; exit(-1); } if(Length() == 0) { cout <<"The list length = 0. Pls insert new Node."<<endl; exit(-1); } // reverse List Node *pre = head->next; // precursor Node Node *cur = pre->next; // current Node Node *nxt = NULL; // successor Node while(cur != NULL) { nxt = cur->next; cur->next = pre; pre = cur; cur = nxt; } // set the tail Node head->next->next = NULL; // set the head Node‘s next field head->next = pre; return OK; }
5. 測試main.cpp
#include <iostream> #include "LinkedList.h" using namespace std; int main() { cout<<"This is Linked List Demo."<<endl; cout<<"Create&Init List:"<<endl; LinkedList *list = new LinkedList(); list->Init(); list->PrintList(); // 順序插入100~109到鏈表中 cout<<"Insert List:"<<endl; int i ; const int base = 100; for(i = base; i < base+10; i ++) { list->Insert(0, i); } list->PrintList(); cout<<"Reverse List:"<<endl; list->ReverseList(); list->PrintList(); return 0; }
6. 測試結果
可以看到已經實現了鏈表基本的插入、打印、反轉等功能。
單鏈表 C++ 實現 - 含虛擬頭節點