链表的浅析与实现
定义:
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
一、单向链表
#ifndef _LISTNODE_H_ #define _LISTNODE_H_ template<class T> class ListNode { public: ListNode(void):link(NULL){}; //构造函数 ListNode(T value):link(NULL),data(value){}; //构造函数 ~ListNode(void){}; //析构函数 void SetLink(ListNode<T>* next); // 设置节点 void SetData(T value); //设置数据 ListNode<T>* GetLink(); //获取节点 T& GetData(); //获取数据 //private: T data; ListNode<T> *link; }; template<class T> T& ListNode<T>::GetData() { return data; } template<class T> ListNode<T>* ListNode<T>::GetLink() { return link; } template<class T> void ListNode<T>::SetData( T value ) { data = value; } template<class T> void ListNode<T>::SetLink( ListNode<T>* next ) { link = next; } #endif
#ifndef _MYLIST_H_ #define _MYLIST_H_ #include "ListNode.h" template <class T> class MyList { public: MyList(); ~MyList(); bool AddTail(T value); //尾部插入 bool RemoveTail(); //删除尾部节点 bool InsertAt(int index,T value); //从某一节点插入 bool RemoveAt(int index); //删除某一节点 T& GetAtDate(int index); //获取某一节点的值 bool IsEmpty(); //判断是否为空 int GetCount(); //获取链表长度 void RemoveAll(); //删除所有节点 ListNode<T>* GetHead(); //获取头节点 ListNode<T>* GetTail();//获取尾节点 ListNode<T>* GetNodeAt(int index);//获取某一个指定节点 //private: ListNode<T>* head; ListNode<T>* tail; }; template <class T> MyList<T>::MyList() { head = new ListNode<T>(); tail = head; tail->SetLink(NULL); } template <class T> MyList<T>::~MyList() { RemoveAll(); delete head; } template <class T> bool MyList<T>::AddTail( T value ) { ListNode<T>* add = new ListNode<T>(value); tail->SetLink(add); tail = tail->GetLink(); tail->SetLink(NULL); if (tail != NULL) { return true; } else { return false; } } template <class T> bool MyList<T>::RemoveTail() { return RemoveAt(this->GetCount()); } template <class T> bool MyList<T>::InsertAt( int index,T value ) { if (index > this->GetCount()-1 || index < 0) { cout<<"A error Point!\n"; return false; } ListNode<T>* current = head; //从头开始寻找出该节点 while (index) { current = current->GetLink(); --index; } ListNode<T>* add = new ListNode<T>(value); add->SetLink(current->GetLink()); current->SetLink(add); if (current->GetLink() != NULL) { return true; } else { return false; } } template <class T> bool MyList<T>::RemoveAt( int index ) { if (index > this->GetCount() || index < 0) { cout<<"A error Point!\n"; return false; } //利用两个指针来协同完成 ListNode<T> *ptr,*NextPtr; ptr = head; //从列表开头开始寻找 NextPtr = ptr->GetLink(); //将NextPtr 置到ptr之后 while (index) { ptr = ptr->GetLink(); NextPtr = ptr->GetLink(); --index; } if (tail == ptr) //如果要删除的节点位于链表的表尾 { tail = ptr; } ptr->SetLink(NextPtr->GetLink()); //将要删除的节点从列表中摘除 delete NextPtr; if (NextPtr == NULL) { return true; } else { return false; } } template <class T> T& MyList<T>::GetAtDate( int index ) { if (index > this->GetCount() || index < 0) { cout<<"A error Point!\n"; } ListNode<T>* ptr; ptr = head->GetLink(); while(index) { ptr = ptr->GetLink(); --index; } return ptr->GetData(); //获取当前节点的值 } template <class T> bool MyList<T>::IsEmpty() { return head->GetLink() == NULL; } template <class T> int MyList<T>::GetCount() { int count = 1; //初始化指针指向第一个节点(非头节点) ListNode<T>* ptr = head->GetLink(); while(ptr->GetLink() != NULL) { ++count; ptr = ptr->GetLink(); } return count; } template <class T> void MyList<T>::RemoveAll() { ListNode<T> * ptr; //当表头节点后还有其他节点时删除这些节点 while(head->GetLink() != NULL) { ptr = head->GetLink(); head->SetLink(ptr->GetLink()); delete ptr; } tail = head; } template <class T> ListNode<T>* MyList<T>::GetHead() { return head; } template <class T> ListNode<T>* MyList<T>::GetTail() { return tail; } template <class T> ListNode<T>* MyList<T>::GetNodeAt( int index ) { if (index > this->GetCount() || index < 0) { cout<<"A error Point!\n"; } ListNode<T>* ptr; ptr = head->GetLink(); while (index) { ptr = ptr->GetLink(); --index; } return ptr; } #endif
#include <iostream> #include <stdio.h> #include "List.h" using namespace std; int main() { MyList<int> listFirst; int n =10; for (int i =0;i<n;i++) { listFirst.AddTail(i); } cout<<"count="<<listFirst.GetCount()<<endl; bool rem; rem = listFirst.RemoveAt(3); cout<<"rem = "<<rem<<endl; int x ; x =listFirst.GetCount(); cout<<"count="<<x<<endl; for (int i =0 ; i< x; i++) { cout<<"data = "<< listFirst.GetAtDate(i)<<endl; } cout<<"tailDate="<<listFirst.GetTail()->GetData(); return 0; }
二、单向循环链表
#ifndef _CIRLIST_H_ #define _CIRLIST_H_ #include "ListNode.h" template<class T> class CirList{ public: CirList(); ~CirList(); bool AddTail(T value); //从尾部添加节点 void RemoveThis(); //移除ptr指向的节点 void RemoveAll(); //清空链表 void SetBegin(); //将ptr 移动到表头 int GetCount(); //获取链表的长度 ListNode<T>* GetPtr(); //获得当前节点 bool IsEmpty(); T GetNext(); //获取ptr指向的节点的值同时让ptr指向下一节点 ListNode<T> *head; ListNode<T> *tail; ListNode<T> *ptr; //记录当前被访问的节点 }; template<class T> CirList<T>::CirList() { head = tail = new ListNode<T>(); ptr = head; head->SetLink(head); } template<class T> CirList<T>::~CirList() { RemoveAll(); delete head; } template<class T> bool CirList<T>::AddTail( T value ) { ListNode<T>* add = new ListNode<T>(value); //新建节点 tail->SetLink(add); //把新建的节点链如链表 tail = tail->GetLink(); //移动tail至新表尾 tail->SetLink(head); //使表尾指针指向表头 if (tail != NULL) return true; else return false; } template<class T> void CirList<T>::RemoveThis() { if (ptr == head) //如果ptr在head处,由于表头节点不可删除。故移动ptr到下一节点 { ptr = ptr->GetLink(); } // Preptr标记ptr的前一节点, delete_ptr标记要删除的节点 ListNode<T>* Preptr = ptr; ListNode<T>* delete_ptr = ptr; //寻找到ptr的前一节点 for (int i = 0;i<this->GetCount();i++) { Preptr = Preptr->GetLink(); } //使得ptr的前一节点指向ptr的后一节点 Preptr->SetLink(ptr->GetLink()); delete delete_ptr; //删除后让ptr向后移动一位 ptr = Preptr->GetLink(); Preptr = NULL; } template<class T> void CirList<T>::RemoveAll() { SetBegin(); //开始从第一个节点删除 int length = GetCount(); //获取链表长度; for (int i =0;i<length;i++) { RemoveThis(); } ptr = head; // 将ptr移动到head处 } template<class T> void CirList<T>::SetBegin() { ptr = head; } template<class T> int CirList<T>::GetCount() { int num =0; if (ptr == NULL) { this->SetBegin(); } ListNode<T>* here = ptr; //记录当前节点位置 while (ptr->GetLink() != here) { ptr = ptr->GetLink(); ++num; } ptr = ptr->GetLink(); //使得ptr回到遍历前的位置 return num; } template<class T> ListNode<T>* CirList<T>::GetPtr() { return ptr; } template<class T> bool CirList<T>::IsEmpty() { return head->GetLink() == head; } template<class T> T CirList<T>::GetNext() { if (ptr == head) //跳过头节点,因为头节点里面不存储有效数据 { ptr = ptr->GetLink(); } T num = ptr->GetData(); //获得数据 ptr = ptr->GetLink(); //顺序移动ptr到下一个节点 return num; } #endif
#include <iostream> #include <stdio.h> #include "CirList.h" using namespace std; int main() { CirList<int> jos; //新建单向循环链表,模拟约瑟夫问题 //向链表中加入1~15 ,代表编号为1~15 的人 for(int i=1;i<16;i++){ jos.AddTail(i); } jos.SetBegin();//开始模拟约瑟夫问题 //记录原始队列的人数,用此人数减一即可得到要删去多少人 //本题中要删去14人 int length = jos.GetCount(); for(int i=1;i<length;i++) { for(int j=0;j<3;j++) jos.GetNext(); jos.RemoveThis(); } cout<<jos.GetNext()<<endl; system("PAUSE"); return 0; }
三、双向循环链表
#ifndef _DOULISTNODE_H_ #define _DOULISTNODE_H_ template<class T> class DoubListNode { public: DoubListNode():link(NULL),prior(NULL){}; DoubListNode(T value):link(NULL),prior(NULL),date(value){}; ~DoubListNode(){}; void SetLink(DoubListNode<T>* next); //设置后继节点 void SetPrior(DoubListNode<T>* pre); //设置前驱节点 void SetDate(T value); //设置节点数据 DoubListNode<T>* GetLink(); //获取后继节点 DoubListNode<T>* GetPrior(); //获取前驱节点 T& GetData(); //获取节点数据 T date; DoubListNode<T>* link; //指向后一个节点 DoubListNode<T>* prior; //指向前一个节点 }; template<class T> void DoubListNode<T>::SetLink(DoubListNode<T> *next) { link = next; } template<class T> void DoubListNode<T>::SetPrior(DoubListNode<T> *pre) { prior = pre; } template <class T > DoubListNode<T>* DoubListNode< T >::GetLink(){ return link; } template<class T> DoubListNode<T> * DoubListNode<T>::GetPrior() { return prior; } template<class T> void DoubListNode<T>::SetDate(T value) { date = value; } template<class T> T& DoubListNode<T>::GetData() { return date; } #endif
#ifndef _DOULIST_H_ #define _DOULIST_H_ #include <stdio.h> #include "DouListNode.h" template<class T> class DouList{ public: DouList(); ~DouList(); bool AddTail(T value); //从尾部添加节点 bool AddHead(T value); //从头部添加节点 void RemoveThis(bool direction); //移除ptr指向的节点 direction决定移除后ptr的移动方向 void RemoveAll(); //清空链表 void SetBegin(); //将ptr 移动到表头 int GetCount(); //获取链表的长度 DoubListNode<T>* GetPtr(); //获得当前节点 bool IsEmpty(); T GetNext(); //获取ptr指向的节点的值同时让ptr指向下一节点 T GetPrior(); //获取ptr指向的节点的值同时让ptr指向上一节点 DoubListNode<T> *head; DoubListNode<T> *tail; DoubListNode<T> *ptr; //记录当前被访问的节点 }; template<class T> DouList<T>::DouList() { head = tail = new DoubListNode<T>; ptr = head; head->SetLink(head); head->SetPrior(tail); } template<class T> DouList<T>::~DouList() { RemoveAll(); delete head; } template<class T> bool DouList<T>::AddHead( T value ) { DoubListNode<T>* add = new DoubListNode<T>(value); //新建节点 add->SetPrior(head); //把新建的节点的前驱节点设置为head add->SetLink(head->GetLink()); //把新建的节点的后继节点设置为head的后继节点 head->GetLink()->SetPrior(add); //把head的后继节点的前驱节点设置为add head->SetLink(add); //更新head的后继节点为add //如果对空链表使用该函数,则应该是更新尾指针 if(tail == head) { tail = head->GetLink(); } if (add != NULL) return true; else return false; } template<class T> bool DouList<T>::AddTail( T value ) { DoubListNode<T>* add = new DoubListNode<T>(value); //新建节点 tail->SetLink(add); //把新建的节点设为当前tail节点的后继节点 add->SetPrior(tail); //将add的前驱节点设置为tail tail = tail->GetLink(); //更新tail节点 tail->SetLink(head); //更新tail节点的后继节点为head head->SetPrior(add); if (tail != NULL) return true; else return false; } template<class T> void DouList<T>::RemoveThis(bool direction) { if (ptr == head) //如果ptr在head处,由于表头节点不可删除。故移动ptr到下一节点 { //如果direction==0 ptr顺着link方向移动,如果dirction==1 ptr顺着prior方向移动 if(direction == 0) ptr = ptr->GetLink(); if(direction == 1) ptr = ptr->GetLink(); } // 新建指针preptr 指向ptr前驱节点 // 新建指针nextptr 指向ptr前驱节点 DoubListNode<T> * preptr = NULL; DoubListNode<T> * nextptr = NULL; preptr = ptr->GetPrior(); nextptr = ptr->GetLink(); // delete_ptr标记要删除的节点 DoubListNode<T>* delete_ptr = ptr; preptr->SetLink(ptr->GetLink()); //将ptr的前驱节点的后继节点指向ptr的后继节点 nextptr->SetPrior(ptr->GetPrior()); //将ptr的后继节点的前驱节点指向ptr的前驱节点 //如果direction==0 ptr顺着link方向移动,如果dirction==1 ptr顺着prior方向移动 if(direction == 0) ptr = nextptr; if(direction == 1) ptr = preptr; delete delete_ptr; } //// template<class T> void DouList<T>::RemoveAll() { SetBegin(); //开始从第一个节点删除 int length = GetCount(); //获取链表长度; for (int i =0;i<length;i++) { RemoveThis(0); } ptr = head; // 将ptr移动到head处 } template<class T> void DouList<T>::SetBegin() { ptr = head; } template<class T> int DouList<T>::GetCount() { int num =0; DoubListNode<T>* here = ptr; //记录当前节点位置 while (ptr->GetLink() != here) { ptr = ptr->GetLink(); ++num; } ptr = ptr->GetLink(); //使得ptr回到遍历前的位置 return num; } template<class T> DoubListNode<T>* DouList<T>::GetPtr() { return ptr; } template<class T> bool DouList<T>::IsEmpty() { return head->GetLink() == head; } //获得ptr指向的结点中的数据,并将cur 向link 方向移动 template<class T> T DouList<T>::GetNext() { if (ptr == head) //跳过头节点,因为头节点里面不存储有效数据 { ptr = ptr->GetLink(); } T num = ptr->GetData(); //获得数据 ptr = ptr->GetLink(); //顺序移动ptr到下一个节点 return num; } //获得ptr指向的结点中的数据,并将cur 向prior 方向移动 template<class T> T DouList<T>::GetPrior() { if (ptr == head) //跳过头节点,因为头节点里面不存储有效数据 { ptr = ptr->GetPrior(); } T num = ptr->GetData(); //获得数据 ptr = ptr->GetPrior(); //顺序移动ptr到下一个节点 return num; } #endif
#include "DouList.h" #include <iostream> using namespace std; int main( ) { DouList<char> planText; DouList<char> cryptograph; DouList<int> key; DouList<char> trans; planText.SetBegin(); planText.AddTail('y'); planText.AddTail('o'); planText.AddTail('u'); planText.AddTail('a'); planText.AddTail('r'); planText.AddTail('e'); planText.AddTail('m'); planText.AddTail('y'); planText.AddTail('b'); planText.AddTail('e'); planText.AddTail('s'); planText.AddTail('t'); planText.AddTail('l'); planText.AddTail('o'); planText.AddTail('v'); planText.AddTail('e'); planText.SetBegin(); cout<<"明文:"<<'\t'; for(int z=0;z<planText.GetCount();z++){ cout<<planText.GetNext()<<" "; } cout<<endl<<endl; key.SetBegin(); //产生密钥链表 for(int i=0;i<6;i++){ key.AddTail(1+rand()%9); } cout<<"密钥:"<<'\t'; for(int i=0;i<key.GetCount();i++){ cout<<key.GetNext()<<" "; } cout<<endl<<endl; planText.SetBegin(); key.SetBegin(); cryptograph.SetBegin(); for(int i=0;i<planText.GetCount();i++){ char c = planText.GetNext(); int num = key.GetNext(); if('a'<=c&&c<='z'-num) c=c+num; else if('z'-num<c&&c<='z') c = c+num-1-'z'+'a'; cryptograph.AddTail(c); } cryptograph.SetBegin(); cout<<"密文:"<<'\t'; for(int j=0; j<cryptograph.GetCount(); j++){ cout<<cryptograph.GetNext()<< " "; } cout<<endl<<endl; trans.SetBegin(); planText.SetBegin(); key.SetBegin(); for(int k=0; k<planText.GetCount(); k++){ char c = cryptograph.GetNext(); int num = key.GetNext(); if('a'<=c-num && c-num<='z') c=c-num; else if('a'>c-num && c>='a') c = 'z'-('a'-c+num)+1; cryptograph.AddTail(c); trans.AddHead(c); } trans.SetBegin(); cout<<"解密:"<<'\t'; for(int k=0;k<trans.GetCount();k++){ cout<<trans.GetPrior()<<" "; } cout<<endl<<endl; system("PAUSE"); return 0; }
海阔凭鱼跃,天高任鸟飞。