链表

链表是将数据元素放在不连续的地址空间中的一种线性表。

单链表的每一个节点包含两部分:

  1. 数据域
  2. 指针域(下一个节点的地址)

链表结构:

  • 一个链表通常有一个“表头”,用来存放第一结点的地址
  • 每一个结点的后面一个结点称为该结点的后继,链表也会有一个“表尾”,表尾没有后继,所以尾结点的指针域为空指针(NULL)

链表

特征:

  • 单链表结点的物理位置不一定连续,单链表逻辑上通过指针实现连续
  • 单链表有一个头结点和一个尾结点,并且只有尾结点没有后继结点,其他结点有且仅有一个后继结点
  • 只有知道了链表的头结点,就可以遍历整个链表

 链表结构

template<typename DataType>class LinkList
{
public:
    LinkList()
    {
        head = new ListNode<DataType>();
    }
    LinkList(ListNode<DataType> *firestNode)
    {
        head = firestNode;
    }
    ~LinkList()
    {
        delete head;
    }
    //在第i个结点后插入结点
    bool insertNode(int index, DataType newData);
    //在表尾添加新的结点
    bool insertNode(DataType newData);
    //删除结点
    bool removeNode(ListNode<DataType>*q);
    //查找指定值的结点并返回地址
    ListNode<DataType>* findNode(DataType value);
    //清空链表
    void cleanLink();
    //获取第i个结点中的数据
    DataType getNodeData(const int index);
    //获取链表长度
    int getLength();
    //查找链表第i个元素
    ListNode<DataType>* getNode(int i);
private:
    ListNode<DataType> *head;//头结点
};

链表结点

template<typename DataType>class ListNode
{
public:
    ListNode()
    {
        next = NULL;
    }
    ListNode(const DataType item, ListNode<DataType> *nodeNext = NULL)
    {
        data = item;
        next = nodeNext;
    }
    ~ListNode()
    {
        next = NULL;
    }
    //获取结点内的数据
    DataType getData()
    {
        return data;
    }
    //获取指针域
    ListNode* getNext()
    {
        return next;
    }
private:
    friend class LinkList<DataType>;        //将LinkList设为友元类,方便对node的成员数据和方法访问
    ListNode<DataType> *next;                //指向下一个结点的指针    
    DATATYPE data;                            //节点中的数据
};

链表插入

单链表的插入操作分两步实现:

  1. 创建一个待插入的结点p,为其分配内存空间,并将其指针域设为NULL
  2. 找到单链表的第i个结点位置,获取它的地址q,将结点p插入在结点q与其后继结点之间

 链表

在第i个结点后插入结点

template<typename DataType> bool LinkList<DataType>::insertNode(int i,DataType newData)
{
    ListNode<DataType> *p = head;                //设置游标指针,初始化为头结点地址
    int j;
    for(j = 1;j<=i-1;j++)                       //查找第i个结点,指针需要移动i-1次
    {
        p = p->next;
        if(p == NULL)                          //如果指针为空,则不存在该结点,或已到表尾
        {

            break;
        }

    }
    if(p==NULL && j<(i-1))                      //指针为空且没有到第i个位置,说明不存在第i个结点
    {
        std::cout<<"插入位置无效!"<<endl;
        return false;
    }
    ListNode<DataType> *node = new ListNode<DataType>(newData);     //建立新结点node      
    node->next = p->next;                                           //将node的next指针赋值为p的后继结点地址
    p->next = node;                                                 //p的后继指针指向node
    return true;
}

 在表尾添加新的结点

template<typename DataType> bool LinkList<DataType>::insertNode(DataType newData)
{
    ListNode<DataType> *p = head;                               //设置游标指针
    ListNode<DataType> *node = new ListNode<DataType>(newData); //创建新结点
    if(node == NULL)                                            //如果新结点内存分配失败,返回false
    {
        return false;
    }
    while(p->next != NULL)                                 //遍历单链表,找到尾结点
    {
        p = p->next;
    }
    p->next = node;                                        //将尾结点next指针指向新结点
    return true;
}

删除结点

template<typename DataType> bool LinkList<DataType>::removeNode(ListNode<DataType> *q)
{
    if(q == NULL)                                       //判断待删除结点是否存在
    {
        std::cout<<"待删除结点不存在!"<<std::endl;
        return false;
    }
    ListNode<DataType> *tempPointer = head;            //设置游标指针,初始化为头结点
    while(tempPointer->next != q)                      //遍历单链表,找到q所指向的结点的前驱结点
    {
        tempPointer = tempPointer->next;
    }
    tempPointer->next = q->next;                       //将q结点的后继结点地址赋值给其前驱结点的next指针
    delete q;                                          //回收结点q的空间
    return true;
}

查找指定值的结点并返回地址

template<typename DataType> ListNode<DataType>* LinkList<DataType>::findNode(DataType value)
{
    ListNode<DataType> *currentPointer = head;               //设置游标指针
    //判定游标指针所指结点的值是否与value相等
    while(currentPointer != NULL && currentPointer->data != value)       
    {
        currentPointer = currentPointer->next;
    }
    if(currentPointer == NULL)                              //判定所找结点是否存在
    {
        std::cout<<"没有找到该结点!程序退出!"<<endl;
        exit(1);
    }else
    {
        return currentPointer;                             //返回所找到的结点的指针
    }        
}

清空链表

template<typename DataType> void LinkList<DataType>::cleanLink()
{
    ListNode<DataType> *current = head;                   //设置游标指针
    while(head->next != NULL)                             //判断head的后继结点是否为NULL
    {
        current = head->next;                             //将current指向head的后继结点
        head->next = current->next;                       //将current的后继地址赋值给head的next域
        delete current;                                   //回收current结点所占的空间
    }
}

获取结点数据

template<typename DataType> DataType LinkList<DataType>::getNodeData(int index)
{
    int linkLength = getLength();    
    if(index < 1 || index > linkLength)
    {
        std::cout<<"结点不存在!"<<std::endl;
        return false;
    }
    else
    {
        ListNode<DataType> *pmove = head->next;
        for(int i = 1;i<index&&pmove;i++)
        {
            pmove = pmove->next;
        }
        return pmove->getData();
    }
}

获取链表长度

template<typename DataType> int LinkList<DataType>::getLength()
{
    int count = 0;
    ListNode<DataType> *p = head->next;
    while(p != NULL)
    {
        p = p->next;
        count++;
    }
    return count;
}

查找链表第i个元素

template<typename DataType> ListNode<DataType>* LinkList<DataType>::getNode(int i)
{
    ListNode<DataType> *p = head->next;
    int j;
    if(i<1 || i>getLength()-1)                //带头结点所以实际节点数需减1
    {
        return false;
    }
    for(j=1;j<i;j++)
    {
        p = p->next;
        if(p == NULL)
        {
            break;
        }
    }
    if(p == NULL && j<i-1)
    {
        return false;
    }
    return p;
}