数据结构-01-链表数据结构之单链表

来源:互联网 发布:java编译手机模拟器 编辑:程序博客网 时间:2024/05/21 10:38

本文中的所有代码均在github上的项目中:List_DataStructure

一.链表:

1.1 链表的概念:

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

1.2 链表的种类:

链表根据每个结点存储的指向下一结点的链接不同而分为几类
单链表:结构最简单的链表,每个结点中都有指向下一结点的地址
双链表:对单链表做了部分加强,每个结点中都有两个地址,分别指向上一结点和下一结点
环形链表:尾结点中存储有头结点的地址,整个链表形成了一个封闭的环

二.单链表:

单链表又名单向链表,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取的方式,从头部开始遍历链表

2.1 单链表的基本结构:

单链表的开始是一个头指针,每个结点中都有指向下一结点的地址,尾结点中的地址为nullptr

这里写图片描述

单链表的C++实现:

1.首先创建单链表的结点类

template<typename Type> class SingleLinkedList;template<typename Type>class SingleLinkedListNode{private:    //将链表类声明为友元    friend typename SingleLinkedList<Type>;    //构造函数和析构函数    SingleLinkedListNode() :pnext(nullptr){}    SingleLinkedListNode(const Type item, SingleLinkedListNode<Type> * next = nullptr) :data(item),pnext(next){}    ~SingleLinkedListNode() {        pnext = nullptr;    }public:    //创建公共方法,用于获取结点中的数据    Type GetData();SingleLinkedListNode<Type>&);private:    //结点类的私有属性,结点数据和下一结点的地址    Type data;    SingleLinkedListNode * pnext;};

2.创建单链表类

#include"SingleLinkedListNode.h"template <typename Type>class SingleLinkedList{public:    //构造函数和析构函数    SingleLinkedList() :head(new SingleLinkedListNode<Type>()){}    ~SingleLinkedList() {        MakeEmpty();        delete head;    }    //对单链表的基本操作    void MakeEmpty();    void Insert(Type item, int i = 0);    void Remove(int i = 0);    void RemoveAll(Type item);    //返回单聊表的基本信息    int length();    Type Get(int i);    //查找和排序    SingleLinkedList<Type> * SequentialSearch(Type item);    //基础功能    void Print();private:    //链表的头节点是私有的    SingleLinkedListNode<Type> *head;};

3.创建一个单链表对象:

SingleLinkedList<int> list;

根据空参构造方法,创建单链表对象时初始化了一个私有的,没有数据的头结点*head

2.2 向单链表中插入数据:

单链表的一个可用的Insert( )方法版本:
该版本不用按照插入位置的不同(头尾体)而分情况实现,比较简洁

//向单链表中插入元素template <typename Type>void SingleLinkedList<Type>::Insert(Type item, int i = 0) {    if (i < 0){        cout << "请输入一个大于0的数" << endl;    }    SingleLinkedListNode<Type> *pmove = head;    SingleLinkedListNode<Type> *pnode = new SingleLinkedListNode<Type>(item);    //循环条件是j<i,且pmove的地址不能为空    for (int j = 0; j < i&&pmove; j++){        pmove = pmove->pnext;    }    //插入点越界    if (pmove == nullptr){        cout << "数据插入位置错误,单链表没那么长!" << endl;    }    pnode->pnext = pmove->pnext;    pmove->pnext = pnode;}

在中间部分插入数据

以中间部分插入为主讨论:

这里写图片描述

1,首先创建两个结点类型指针pmove 和pnode
2,将pmove指针移动到插入点,如上图,插入位置为a2,a3之间,pmove指向a2
3,变更结点中存储的地址以实现结点插入

pnode->pnext = pmove->pnext; //第一步pmove->pnext = pnode; //第二步

第一步:待插入节点pnode的下一结点地址pnext指向a3,a3的地址为a2结点的下一结点地址pnext,也是pmove的pnext,即pmove->pnext
第二步:更改a2结点的下一结点地址pnext,使其指向待插入节点pnode

如上图所示,s为待插入节点pnode,p为插入点位置pmove

在头部插入数据

这里写图片描述

在尾部插入数据

这里写图片描述

测试单链表的插入方法:

int main() {    SingleLinkedList<int> list;    //向链表中插入20个数据    for (int i = 0; i < 20; i++)    {        list.Insert(i*4,i);    }    //在链表头部插入数据    list.Insert(10,0);    //在链表尾部插入数据    list.Insert(100,21);    list.Print();    cin.get();    return 0;}

执行结果:

这里写图片描述

2.3 删除单链表中的数据:

执行原理与添加数据相似,创建两个结点类型指针pdel和pmove
pdel指向待删除元素,pmove指向待删除结点的前一个结点

//删除单链表中的元素template <typename Type>void SingleLinkedList<Type>::Remove(int i = 0) {    if (i < 0){        cout << "请输入一个大于0的数" << endl;    }    SingleLinkedListNode<Type> *pmove = head, *pdel;    for (int j = 0; j < i&&pmove->pnext; j++){        pmove = pmove->pnext;    }    if (pmove->pnext == nullptr){        cout << "删除出错,链表没有那么长!" << endl;    }    pdel = pmove->pnext;    pmove->pnext = pdel->pnext;    delete pdel;}

2.3 单链表的其他方法:

2.3.1 销毁单链表

析构函数调用了此方法

//删除单链表template <typename Type>void SingleLinkedList<Type>::MakeEmpty() {    SingleLinkedListNode<Type> *pdel;    while (head->pnext != nullptr)    {        pdel = head->pnext;        head->pnext = pdel->pnext;        delete pdel;    }}

2.3.2 返回单链表长度

//返回单链表长度template<typename Type>int SingleLinkedList<Type>::length() {    SingleLinkedListNode<Type> *pmove = head->pnext;    int count = 0;    while (pmove != nullptr) {        pmove = pmove->pnext;        count++;    }    return count;}

2.3.3 打印单链表中的所有数据

//打印单链表中的所有数据template<typename Type>void SingleLinkedList<Type>::Print() {    SingleLinkedListNode<Type> *pmove = head->pnext;    cout << endl << "head";    while (pmove != nullptr)    {        cout << "->" << pmove->data;        pmove = pmove->pnext;    }    cout << "-over" << endl;}