所实现的单链表的结构如下图所示:
头文件:SList.h
#include<iostream> #include<cassert> using namespace std; typedef enum{FALSE,TRUE}Status; template<class Type> class List; template<class Type> class ListNode { friend class List<Type>; //友元类可以访问该类的成员 private: Type data; ListNode *next; public: ListNode() :data(Type()), next(NULL){} ListNode(Type d, ListNode<Type> *n = NULL) :data(d), next(n){} void SetData(Type d){ data = d; } Type GetData()const{ return data; } ~ListNode(){} }; template<class Type> class List { private: ListNode<Type> *first; //单链表的头指针 ListNode<Type> *last; //单链表的尾指针 size_t size; //单链表的长度 protected: /*ListNode<Type> * _BuyNode(const Type &x,ListNode<Type> *_Narg = NULL)//--->有待解决 { ListNode<Type> *s = new ListNode<Type>(x,_Narg); }*/ ListNode<Type> * _BuyNode(const Type &x) { ListNode<Type> *s = new ListNode<Type>(x); assert(s != NULL); return s; } public: List() { first = last = _BuyNode(0); size = 0; } ~List() { destory(); } Status push_back(const Type &x) { ListNode<Type> *s = _BuyNode(x); last->next = s; last = s; size++; return TRUE; } void show_list() { ListNode<Type> *s = first->next; while (s != NULL) { cout << s->data << "->"; s = s->next; } cout << "NULL" << endl; } Status push_front(const Type &x) { ListNode<Type> *s = _BuyNode(x); s->next = first->next; first->next = s; if (size == 0) last = s; size++; return TRUE; } Status pop_back() { if (first == last)//size == 0 { cout << "单链表已空,无法尾删" << endl; return FALSE; } ListNode<Type> *s = first; while (s->next != last) { s = s->next; } delete last; s->next = NULL; last = s; size--; return TRUE; } Status pop_front() { if (first == last)//size == 0 { cout << "单链表已空,无法头删" << endl; return FALSE; } ListNode<Type> *s = first->next; first->next = s->next; delete s; if (size == 1) last = first; size--; return TRUE; } ListNode<Type>* find(const Type &x) //返回所查元素的地址:麻烦于(delete_val,next,prio) { ListNode<Type> *s = first->next; while (s != NULL && s->data != x) { s = s->next; } return s; } /*ListNode<Type>* find(const Type &x)//返回所查元素的前一个地址 { ListNode<Type> *s = first; while (s->next != NULL &&s->next->data != x) { s = s->next; } if (s->next == NULL) return NULL: else return s; }*/ ////方法一 //Status delete_val(const Type &x)//常规方法 //{ // ListNode<Type> *s = find(x); // if (s == NULL) // { // cout << "该元素不存在,无法删除" << endl; // return FALSE; // } // if (s == first->next) // pop_front(); // else if (s == last) // pop_back(); // else // { // ListNode<Type> *p = first; // while (p->next != s) //寻找所查元素的前一个节点 // { // p = p->next; // } // p->next = s->next; // delete s; // size--; // } // return TRUE; //} //方法二 Status delete_val(const Type &x) { ListNode<Type> *s = find(x); if (s == NULL) { cout << "该元素不存在,无法删除" << endl; return FALSE; } if (s == last) pop_back();//--------------->尾节点后面没有节点,无法用后面节点的值覆盖它,所以单独定义 else { ListNode<Type> *p = s->next; s->data = p->data;//后面节点的值覆盖它的值 s->next = p->next;//将后面的节点删除 delete p; size--; } return TRUE; } ListNode<Type>* next(const Type &x) { ListNode<Type> *s = find(x); if (s == NULL) { cout << "该元素不存在" << endl; return NULL; } if (s == last) { cout << "该元素没有后继" << endl; return NULL; } else { return s->next; } } ListNode<Type>* prio(const Type &x) { ListNode<Type> *s = find(x); if (s == NULL) { cout << "该元素不存在" << endl; return NULL; } if (s == first->next) { cout << "该元素没有前驱" << endl; return NULL; } else { ListNode<Type> *p = first; while (p->next != s) { p = p->next; } return p; } } //单链表逆置:将链表从第一个元素处断开(第一个节点成为最后一个节点) //将链表之后节点的值,依次进行头插(值头插之后记得删除节点) void reserve() { if (size == 0 || size == 1) return; ListNode<Type> *s = first->next; ListNode<Type> *p = s->next; last = s; last->next = NULL;//第一个节点成为最后一个节点 while (p != NULL) { s = p; p = p->next; //push_front(s->data); //delete s; s->next = first->next; first->next = s; } } //按值插入:先排好序,然后寻找要插入元素的前一个位置,在该位置之后插入该元素 Status insert_val(const Type &x) { sort(); ListNode<Type> *p = _BuyNode(x); ListNode<Type> *s = first; while (s->next != NULL && s->next->data < p->data)//找到所插元素的前一个节点 { s = s->next; } if (s->next == NULL)//这时候,所插元素是最大的,尾插即可(未找到要插入的前一个位置) push_back(x); else { p->next = s->next; s->next = p; size++; } return TRUE; } //排序思想:将链表从第一个节点处断开(第一个成为最后一个节点) //将之后的节点依次按值进行插入(注意值插入之后,节点要释放) void sort() { if (size == 0 || size == 1) return; ListNode<Type> *s = first->next; ListNode<Type> *p = s->next; last = s; //------->第一个节点成为最后一个节点 last->next = NULL; while (p != NULL) //------->断开之后依次按值进行插入 { s = p; //保存要插入的节点 p = p->next; //为下一次插入做准备 insert_val(s->data);//进行插入 delete s; //释放节点,防止内存泄露 } } size_t lenth() { return size; } /* void clear() { ListNode<Type> *s = first; ListNode<Type> *p; while (size--) //p始终指向第一个节点(总是删除第一个节点,删除size次) { p = s->next; s->next = p->next; delete p; } size = 0; last = fisrt; } */ void clear() { ListNode<Type> *s = first->next;//p始终指向第一个节点(总是删除第一个节点,删除size次) while (s != NULL) { first->next = s->next; delete s; s = first->next; } size = 0; last = first; } void destory() { clear(); delete first; first = last = NULL; } };测试文件:main.cpp
#include"SList.h" int main() { List<int> mylist; int item; int n; int select = 1; ListNode<int> *p; while (select) { cout << "*************************************** *" << endl; cout << "*[1] push_back [2] push_front *" << endl; cout << "*[3] show_list [4] pop_back *" << endl; cout << "*[5] pop_front [6] insert_val *" << endl; cout << "*[7] lenth [8] find *" << endl; cout << "*[9] merge [10] delete_val*" << endl; cout << "*[11] sort [12] reserve *" << endl; cout << "*[13] next [14] clear *" << endl; cout << "*[15] prio [0] quit_system*" << endl; cout << "请选择:>"; cin >> select; switch (select) { case 1: cout << "请输入要插入的元素(-1结束):>"; while (cin >> item, item != -1) { mylist.push_back(item); } break; case 2: cout << "请输入要插入的元素(-1结束):>"; while (cin >> item, item != -1) { mylist.push_front(item); } break; case 3: mylist.show_list(); break; case 4: mylist.pop_back(); break; case 5: mylist.pop_front(); break; case 6: cout << "请输入要插入的元素:"; cin >> item; mylist.insert_val(item); break; case 7: cout << "长度为:" << mylist.lenth() << endl; break; case 8: cout << "请输入要查找的元素:"; cin >> item; if (mylist.find(item)) cout << "it's found" << endl; else cout << "it's not exist" << endl; break; case 9: cout << "请输入要删除的位置:"; cin >> n; //mylist.delete_pos(n,item); break; case 10: cout << "请输入要删除的元素:"; cin >> item; mylist.delete_val(item); break; case 11: mylist.sort(); break; case 12: mylist.reserve(); break; case 13: cout << "请输入要查找后继的元素:"; cin >> item; p = mylist.next(item); if (p != NULL) cout << p->GetData() << endl; break; case 14: mylist.clear(); break; case 15: cout << "请输入要查找前驱的元素:"; cin >> item; p = mylist.prio(item); if (p != NULL) cout << p->GetData() << endl; break; default: break; } } system("pause"); return 0; }
其中难点也是最有意思的地方在于:排序(sort)以及单链表逆置(reverse)的实现
二者的实现具有异曲同工之妙;
排序:将原来的链表从第一个节点处断开,一分为二,第一个节点以及头结点成为一个单独的链表,接着将剩余的节点依次按值进行插入
链表逆置:将原来的链表从第一个节点处断开,一分为二,第一个节点以及头结点成为一个单独的链表,接着将剩余的节点依次进行头插
头插和头删有注意点:
push_front():当插入的是第一个节点时 (尾指针要指向该节点)
pop_front ():当删除的是最后一个节点时(尾指针要指向头结点)
find()函数:
返回所查元素的地址:(按值删除-->谷歌面试题)
1:重新找一遍,定位到前一个元素的位置,然后删除所要删除的元素
2:将所要删除元素后面的元素p覆盖要删除的元素,然后将p删除
返回所查元素的前一个元素的地址(按值删除delete_val()时很简单)