链表的浅析与实现

定义:

  链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

一、单向链表

#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
ListNode.h
#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 
List.h
#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;
}
test.cpp

 二、单向循环链表

#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
CirList.h
#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;  
}
test.cpp

 三、双向循环链表

#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
DoubListNode.h
#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
DouList.h
 
#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;  
}  
test.cpp

 

posted @ 2017-02-19 18:01  沉舟侧畔  阅读(186)  评论(0编辑  收藏  举报