c++資料結構連結串列和雙頭連結串列的實現
阿新 • • 發佈:2020-12-04
連結串列的基本概念不加以贅述,看看雙頭連結串列的定義如下:
在一個長度為L的連結串列List中,Input: head tail --->在List中查詢head和tail值的連結串列的節點,從tail節點往後的連結串列連線到List的頭部去,然後改變tail節點的next-->head,圖如下:
下面看看c++版本的實現:
#ifndef LIST_H_ #define LIST_H_ #include<iostream> #include<array> #include<cassert> template<typename T> class List { protected: struct Node { T data; struct Node* parents; struct Node* next; Node(T d) :data(d) { parents = nullptr; next = nullptr; } Node() = default; }; using node = struct Node; using pnode = struct Node*; void delete_list(); std::array<pnode, 2>A;//儲存環路的兩個節點 pnode intersection{ nullptr };//儲存相交位置的節點 bool flag;//判斷是否存在環路得標誌位 bool flag2{ false };//判斷是否轉換為雙頭連結串列 void insert(pnode p); public: pnode phead; //雙頭連結串列得頭 pnode phead1; pnode phead2; List() = default;//default construct function List(pnode p1) :phead(p1), phead1(nullptr), phead2(nullptr) { phead = nullptr; phead->next = nullptr; phead->parents = nullptr; phead1 = nullptr; phead1->next = nullptr; phead1->parents = nullptr; phead2 = nullptr; phead2->next = nullptr; phead2->parents = nullptr; A[0] = A[1] = nullptr; } List(T num); List(List<T>& c); List<T>& operator=(List<T>& c); T& operator[](int index); bool INTERSEC() const;//判斷是否相交 std::size_t Len();//返回連結串列長度 //轉換為單鏈表 void conver_to_list(); void insert(T n); pnode find(T data); std::size_t find_count(T c);//返回查詢節點比較的次數 void print_list(); void convert_to_double(T m, T n);//轉換為對應得雙頭連結串列 //找到環路節點 void find_loop() const; bool empty(); ~List() { if (flag2 == true) { conver_to_list(); delete_list(); } else if (flag2 == false) { delete_list(); } } }; template <typename T> void List<T>::delete_list() { pnode p = nullptr; if (phead != NULL) { while (phead) { p = phead->next; delete phead; phead = p; } } } template <typename T> List<T>::List(T num) { phead = new node(num); } template <typename T> List<T>::List(List<T>& c) { this->phead = c->phead; } template <typename T> List<T>& List<T>::operator=(List<T>& c) { this->phead = c.phead; return *this; } template <typename T> T& List<T>::operator[](int index) { if (index < 0) { std::cout << "INDEX Error" << std::endl; } else { auto p2 = this->phead; for (size_t i = 0; i < index; i++) { p2 = p2->next; } return p2->data; } } template<typename T> bool List<T>::INTERSEC() const { if (phead1 == nullptr && phead2 == nullptr) { throw "Please convert to a double-ended linked list first"; } else { if (intersection != nullptr) { std::cout << "存在相交的節點,相交的節點的值是:" << intersection->data << std::endl; return true; } std::cout << "不相交" << std::endl; } return false; } template<typename T> inline std::size_t List<T>::Len() { std::size_t size = 0; pnode p1 = phead; while (p1 != nullptr) { size++; } return size; } template<typename T> void List<T>::conver_to_list() { if (phead1 != nullptr || phead2 != nullptr) { //對於輸入的m==n在連結串列的首尾節點的時候的進行轉換為原來的連結串列 if (phead1 != nullptr && phead2 == nullptr) { //沒有環路m==n的時候 if (flag == false) {//在連結串列尾節點的時候 if (phead1 == phead) { phead1 = phead2 = nullptr; } //在連結串列頭部的時候 else { pnode pcur = phead1; while (pcur->next != phead) { pcur = pcur->next; } pcur->next = nullptr; phead->next = phead1; phead->parents = nullptr; phead1->parents = phead; phead1 = phead2 = nullptr; } } //存在環路 else if (flag == true) { assert(A[0] != A[1]); //end在連結串列的末尾的時候 A[1]->next = nullptr; phead1 = phead2 = nullptr; } } else if (phead1 == nullptr && phead2 != nullptr) { assert(flag == true); //first在頭部end在中間的時候 pnode pcur = phead2; while (true) { if (pcur->next == phead) { pcur->next = nullptr; break; } pcur = pcur->next; } A[1]->next = nullptr; A[1]->next = phead2; phead2->parents = A[1]; phead1 = phead2 = nullptr; } //對於輸入m==n但是在連結串列的中間位置的時候進行轉化為原來的list else if (phead1 != nullptr && phead2 != nullptr) { if (phead1 != phead2) { //處理m==n但是在連結串列中間的時候(注意:無環路) if (flag == false) { //先找相同的節點然後把phead2的部分拉過去到後面即可 pnode pcur1 = phead1; pnode pcur2 = phead2; pnode pcur3 = nullptr; while (true) { if (pcur1 == pcur2) { pcur2->next = nullptr; pcur3 = pcur1; break; } if (pcur1->next != nullptr) { pcur1 = pcur1->next; } else if (pcur2->next != nullptr) { pcur2 = pcur2->next; } } pnode pcur4 = phead2; while (pcur4->next != pcur3) { pcur4 = pcur4->next; } pcur4->next = nullptr; pcur3->next = phead2; phead2->parents = pcur3; phead1 = phead2 = nullptr; } //處理不等於的時候的情形(這是一般的情況下):兩個節點既不相等並且兩個節點都不在頭部或者末尾的地方 else { assert(A[0] != A[1]); A[1]->next = nullptr; //刪除phead2的指向 pnode pcur1 = phead2; while (true) { if (pcur1->next == intersection) { pcur1->next = nullptr; break; } pcur1 = pcur1->next; } A[1]->next = phead2; phead2->parents = A[1]; phead1 = phead2 = nullptr; } } //first在頭部 end在尾部的時候 else if (phead1 == phead2) { A[1]->next = nullptr; phead->parents = nullptr; phead1 = phead2 = nullptr; } } flag2 = false; } assert(phead1 == nullptr && phead2 == nullptr); } template <typename T> void List<T>::insert(T n) { //尾插法建立雙向連結串列 if (phead == nullptr) { phead = new node(n); } else { pnode pnew = new node(n); //尋找插入位置 pnode pcur = phead; while (pcur->next != nullptr) { pcur = pcur->next; } pcur->next = pnew; pnew->parents = pcur; } } template<typename T> void List<T>::insert(pnode p) { if (phead == nullptr) { phead = p; } else { pnode pnew = p; //尋找插入位置 pnode pcur = phead; while (pcur->next != nullptr) { pcur = pcur->next; } pcur->next = pnew; pnew->parents = pcur; } } template <typename T> typename List<T>::pnode List<T>::find(T data) { pnode pcur = phead; while (pcur != nullptr) { if (pcur->data == data) { return pcur; } pcur = pcur->next; } return nullptr; } template<typename T> std::size_t List<T>::find_count(T c) { //確保phead並沒有發生改變 pnode pcur = phead; std::size_t count = 0; while (pcur != nullptr) { count++; if (pcur->data == c) { return count; } pcur = pcur->next; } return 0; } template <typename T> void List<T>::print_list() { if (empty()) { std::cout << "This is empty list" << std::endl; } else { pnode pcur = phead; while (pcur != nullptr) { std::cout << "data:" << pcur->data << "\t"; if (pcur->next != nullptr) { std::cout << "next-data:" << pcur->next->data << "\t"; } if (pcur->parents != nullptr) { std::cout << "parent-data" << pcur->parents->data << std::endl; } pcur = pcur->next; } } } template<typename T> void List<T>::convert_to_double(T m, T n) { /*T m, n; std::cout << "請輸入m,n得值是多少:" << std::endl; std::cin >> m >> n;*/ //查詢對應得節點 pnode phead_m = find(m); pnode phead_n = find(n); if (phead_m == nullptr || phead_n == nullptr) { flag = false;//不存在環路 } //如果查詢到得是一樣值 else if (phead_m == phead_n) { flag = false;//不存在環路但是可以建立雙頭連結串列 //case1 查詢到得節點在list得頭部節點上面 if (phead_m == phead) { pnode pcur = phead_m->next; phead1 = pcur; phead2 = nullptr; pcur->parents = nullptr; while (pcur->next != nullptr) { pcur = pcur->next; } pcur->next = phead_m; phead_m->parents = pcur; phead_m->next = nullptr; } //case2 查詢到得兩個節點都是list得尾部 else if (phead_m->next == nullptr) { phead1 = phead; phead2 = nullptr; } //case3 查詢得節點既不在連結串列得頭部 也不再連結串列得尾部節點 else if (phead_m->next != nullptr && phead_m->parents != nullptr) { std::cout << "In middle with list" << std::endl; pnode pcur = phead_m->next; phead1 = phead; pcur->parents = nullptr; phead2 = pcur; while (pcur->next != nullptr) { pcur = pcur->next; } pcur->next = phead_m; //不修改父節點這個時候對於phead_m擁有兩個父節點 phead_m->next = nullptr; //相交 intersection = phead_m; } } //如果查詢的是兩個完全不一樣的值的時候 else if (phead_m != phead_n) { /*一個節點在頭一個節點在尾部的時候 一個節點在尾部(頭部),另一個節點在中間的時候 兩個節點都在中間的時候 判斷哪個節點在前哪個節點在後*/ //如果不等於必然存在環路 flag = true; //case1判斷前後關係並且進行調整 pnode first = new node, end = new node; std::size_t c1 = find_count(m); std::size_t c2 = find_count(n); if (c1 > c2) { first = phead_n; end = phead_m; } else if (c2 > c1) { first = phead_m; end = phead_n; } //case2 一個節點在頭部一個節點在尾部的時候(不相交) //存放環路節點 A[0] = first; A[1] = end; std::cout << first->data << "\t" << end->data << std::endl; if (first->parents == nullptr && end->next == nullptr) { first->parents = end; end->next = first; phead1 = phead2 = first; } //case3 first節點在頭部,end節點在中間的時候,把end後面的拉過去 end->next=first即可(不相交) else if (first->parents == nullptr && end->next != nullptr) { pnode pre = end->next; phead1 = nullptr;//第一個頭節點 end->next = first;//建立環路 pnode pre2 = pre; while (pre->next != nullptr) { pre = pre->next; } pre->next = first; pre2->parents = nullptr; phead2 = pre2; } //case4 end在尾部 first在中間的時候(不相交) else if (end->next == nullptr && (first->parents != nullptr && first->next != nullptr)) { phead1 = phead; end->next = first; phead2 = nullptr; } //case5 first 和end 節點都在中間的時候(相交) else if ((first->next != nullptr && first->parents != nullptr) && (end->next != nullptr && end->parents != nullptr)) { phead1 = phead; pnode pre = end->next; pnode pre2 = pre; pre2->parents = nullptr; while (pre->next != nullptr) { pre = pre->next; } pre->next = first; end->next = first; first->parents = end; phead2 = pre2; intersection = first; } } flag2 = true; } template<typename T> void List<T>::find_loop() const { if (flag == false) { std::cout << "不存在環路" << std::endl; } else if (flag == true) { std::cout << "環路的首部是:" << A[0]->data << "\t" << "環路的尾部是:" << A[1]->data << std::endl; } } template <typename T> bool List<T>::empty() { if (phead == nullptr) { return true; } return false; } #endif