数据结构 之 链表

在这里插入图片描述

在介绍链表之前,先简单介绍一下缓存机制的三种策略:1、先进先出策略(FIFO),2、最少使用策略(LFU),3、最近最少使用策略(LRU)。单链表、循环链表、双向链表是我们最为常见的三种链表结构,一个链表是由多个链表节点连接而成,在单链表中,每个节点包含两个域:用来存储数据的数据域以及用来连接下一个节点的指针域(next),而在双向链表中指针域上不仅包含连接下一个节点的指针(next),还包含连接上一个节点的指针(pre)。另外,每个链表都会有个头指针,用来指向链表的第一个节点也就是链表的基地址,而在循环链表中最后一个节点的next指针指向的不是NULL,而是链表头指针,且双向循环链表中的头指针的prev指针指向的链表的最后一个节点。链表的插入和删除只需要考虑相邻节点指针的改变即可,所以时间复杂度为O(1),效率十分高,但是链表的随机访问的效率相对要低很多,因为链表无法像数组一样,通过首地址和下标,利用寻址公式直接计算得出对应的内存地址,而是需要指针一个节点一个节点的依次遍历,直到找到相应的节点为止,所以链表的随机访问时间复杂度为O(n),这里需要注意的是,双向链表如果要插入或删除指定节点时比单链表要高效多,虽然此时双向链表的时间复杂度为O(1)。链表相对于数组的优点是删除和插入相对高效,内存分配没有连续空间的要求,但缺点也很明显,节点中包含指针域,浪费内存,还有就是频繁的申请释放内存,容易产生内存碎片。结构如图所示:
这里写图片描述
不多说,直接上代码:

#include <iostream>
#include <stdlib.h>

template <class T>
class Node
{
public:
    T data;
    Node(T& item);
    Node<T>* next;
    Node<T>* pre;
};

template<class T>
class LinkList
{
public:
    LinkList();
    ~LinkList();
    int getSize(void);
    bool IsEmpty(void);
    int gotoNext(void);
    int setPostion(int pos);
    int getPostion(void);
    int InsertNodeBefore(T& data);
    int InsertNodeAfter(T& data);
    void DeleteNode(void);
    void getCurrNodeData(T& data);
    void setCurrNodeData(T& data);
    void clear();
    void print();

private:
    Node<T>* head;
    Node<T>* currNode;
    int size;
    int position;
    void freeNode(Node<T>* p);
};

#endif
// LinkedList.cpp : 定义控制台应用程序的入口点。

#include "stdafx.h"
#include "LinkedList.h"

/* 链表节点构造函数 */
template <class T>
Node<T>::Node(T& item)
{
    data = item;
    next = NULL;
    pre = NULL;
}

/* 链表构造函数 */
template <class T>
LinkList<T>::LinkList()
{
    head = NULL;
    currNode = NULL;
    size = 0;
    position = -1;
}

/* 链表析构函数 */
template <class T>
LinkList<T>::~LinkList()
{
    clear();
}

/* 获取链表长度 */
template <class T>
int LinkList<T>::getSize(void)
{
    return size;
}

/* 判断链表是否为空 */
template <class T>
bool LinkList<T>::IsEmpty(void)
{
    return size==0?true:false;
}

/* 移动到下个节点,返回下个节点的位置值 */
template <class T>
int LinkList<T>::gotoNext(void)
{
    if(NULL == head)
    {
        return -1;
    }

    if(NULL == currNode)
    {
        return -1;
    }
    else
    {
        currNode = currNode->next;
        position = (position+1+1)%(size);
    }

    return position;
}

/* 将当前节点移动到指定节点值 */
template <class T>
int LinkList<T>::setPostion(int pos)
{
    if(pos >= size||pos < 0)
    {
        return -1;
    }

    position = 0;
    currNode = head;

    for(int i = 0; i < pos;i++)
    {
        position++;
        currNode = currNode->next;
    }

    return position;
}

/* 获取当前节点的位置 */
template <class T>
int LinkList<T>::getPostion(void)
{
    return position;
}

/* 在当前节点前插入新节点 */
template <class T>
int LinkList<T>::InsertNodeBefore(T& data)
{
    Node<T>* p = new Node<T>(data);

    if(0 == size)
    {
        head = p;
        head->next = head;
        head->pre = head;
        currNode = head;
        position++;
    }
    else
    {
        currNode->pre->next = p;
        currNode->pre = p;
        p->next = currNode;
        p->pre = currNode->pre->next; 

        if(head == currNode)
        {
            head = p;
        }
        currNode = p;
    }

    size++;

    return size;
}

/* 在当前节点后插入新节点 */
template <class T>
int LinkList<T>::InsertNodeAfter(T& data)
{
    Node<T>* p = new Node<T>(data);

    if(0 == size)
    {
        head = p;
        head->next = head;
        head->pre = head;   
        currNode = p;
    }
    else
    {
        currNode->next->pre = p; 
        p->next = currNode->next ;
        currNode->next = p;
        p->pre = currNode; 
        currNode = p;
    }

    size++;
    position++;
    return size;
}

/* 删除当前节点 */
template <class T>
void LinkList<T>::DeleteNode(void)
{
    if(0 == size)
    {
        return;
    }

    Node<T>* p = currNode;

    currNode->pre->next = currNode->next;
    currNode->next->pre = currNode->pre;
    if(head == currNode)
    {
        head = currNode->next;
    }

    currNode = currNode->next;
    freeNode(p);
    size--;

    return ;
}

/* 释放指定节点的内存 */
template <class T>
void LinkList<T>::freeNode(Node<T>* p)
{
    if(!p)
    {
        delete p;
    }

    return;
}

/* 获取当前节点的数据 */
template <class T>
void LinkList<T>::getCurrNodeData(T& data)
{
    if(currNode)
    {
        data = currNode->data;
    }

    return ;
}

/* 修改当前节点的数据 */
template <class T>
void LinkList<T>::setCurrNodeData(T& data)
{
    if(currNode)
    {
        currNode->data = data;
    }

    return ;
}

/* 清空链表 */
template <class T>
void LinkList<T>::clear()
{
    Node<T>* p = currNode;

    for(int i = 0;i < size;i++)
    {
        p = p->next;
        freeNode(currNode);
        currNode = p;
    }

    head = NULL;
    currNode = NULL;
    size = 0;
    position = -1;

    return;
}

template <class T>
void LinkList<T>::print()
{
    Node<T>* p = head;

    for(int i = 0;i < size;i++)
    {
        std::cout<<"data = "<<p->data<<std::endl;
        p = p->next;
    }

    std::cout<<"====================================== "<<std::endl;
    return;
}

int main(int argc, _TCHAR* argv[])
{
    int a = 10,b=20,c=30,d=40,e=50;

    LinkList<int> linklist;
    
    linklist.InsertNodeAfter(a);
    linklist.InsertNodeAfter(b);
    linklist.InsertNodeAfter(c);
    linklist.InsertNodeAfter(d);
    linklist.InsertNodeAfter(e);
    linklist.print();

    std::cin.get();
	return 0;
}

运行结果如下图:
这里写图片描述

另外附上单向不循环链表的代码,供读者对比区别使用:

// 单链表.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdlib.h>
#include <iostream>

template <class T>
class Node
{
public:
    T data;
    Node(T& item);
    Node<T>* next;
};

template<class T>
class LinkList
{
public:
    LinkList();
    ~LinkList();
    int getSize(void);
    bool IsEmpty(void);
    int gotoNext(void);
    int getPostion(void);
    int InsertNode(T& data);
    int DeleteNode(void);
    void getCurrNodeData(T& data);
    void setCurrNodeData(T& data);
    void clear();
    void print();

private:
    Node<T>* head;
    Node<T>* currNode;
    int size;
    int position;
    void freeNode(Node<T>* p);
};

/* 链表节点构造函数 */
template <class T>
Node<T>::Node(T& item)
{
    data = item;
    next = NULL;
}

/* 链表构造函数 */
template <class T>
LinkList<T>::LinkList()
{
    head = NULL;
    currNode = NULL;
    size = 0;
    position = -1;
}

/* 链表析构函数 */
template <class T>
LinkList<T>::~LinkList()
{
    clear();
}

/* 获取链表长度 */
template <class T>
int LinkList<T>::getSize(void)
{
    return size;
}

/* 判断链表是否为空 */
template <class T>
bool LinkList<T>::IsEmpty(void)
{
    return size==0?true:false;
}

/* 移动到下个节点,返回下个节点的位置值 */
template <class T>
int LinkList<T>::gotoNext(void)
{
    if(NULL == head)
    {
        return -1;
    }

    if(NULL == currNode)
    {
        return -1;
    }
    else
    {
        currNode = currNode->next;
        position++
    }

    return position;
}

/* 获取当前节点的位置 */
template <class T>
int LinkList<T>::getPostion(void)
{
    return position;
}

/* 在当前节点前插入新节点 */
template <class T>
int LinkList<T>::InsertNode(T& data)
{
    Node<T>* p = new Node<T>(data);

    if(0 == size)
    {
        head = p;
        head->next = NULL;
        currNode = p;
        
    }
    else
    {
        p->next = currNode->next;
        currNode->next = p;
        currNode = p;
    }

    size++;
    position++;
    return size;
}


/* 删除当前节点 */
template <class T>
int LinkList<T>::DeleteNode(void)
{
    if(0 == size)
    {
        return -1;
    }
    
    Node<T>* p = head;
    Node<T>* tmp;
    for(int i = 0;i < size;i++)
    {
        if(NULL == p)
        {
            return -1;
        }

        if(p->next == currNode)
        {
            p->next = currNode->next;
            break;
        }

        p = p->next;
    }

    tmp = currNode;

    if(currNode == head)
    {
        head = currNode->next;
    }

    if(NULL == currNode->next)
    {
        position--;
        currNode = p;
    }
    else
    {
        currNode = currNode->next;
    }
    

    freeNode(p);
    size--;
    if(0 == size)
    {
       position = -1;
    }

    return 0;
}

/* 释放指定节点的内存 */
template <class T>
void LinkList<T>::freeNode(Node<T>* p)
{
    if(!p)
    {
        delete p;
    }

    return;
}

/* 获取当前节点的数据 */
template <class T>
void LinkList<T>::getCurrNodeData(T& data)
{
    if(currNode)
    {
        data = currNode->data;
    }

    return ;
}

/* 修改当前节点的数据 */
template <class T>
void LinkList<T>::setCurrNodeData(T& data)
{
    if(currNode)
    {
        currNode->data = data;
    }

    return ;
}

/* 清空链表 */
template <class T>
void LinkList<T>::clear()
{
    if(0 == size)
    {
        return;
    }

    Node<T>* p = head;
    Node<T>* tmp = head->next;
    while(p)
    {
        freeNode(p);
        p = tmp;
        if(tmp)
        {
            tmp = tmp->next;
        }
    }

    head = NULL;
    currNode = NULL;
    size = 0;
    position = -1;

    return;
}

template <class T>
void LinkList<T>::print()
{
    if(0 == size)
    {
        return;
    }

    Node<T>* p = head;
    Node<T>* tmp = head->next;
    while(p)
    {
        std::cout<<p->data<<std::endl;
        p = tmp;
        if(tmp)
        {
            tmp = tmp->next;
        }
    }

    return;
}

int main(int argc, _TCHAR* argv[])
{
    int a = 10,b=20,c=30,d=40,e=50;
    LinkList<int> list;
    list.InsertNode(a);
    list.InsertNode(b);
    list.InsertNode(c);
    list.DeleteNode();
    list.InsertNode(d);
    list.InsertNode(e);
    list.print();
    std::cin.get();
	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chiang木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值