单向链表LinkedList详解

单链表

简介

什么是单链表

单链表(Singly Linked List)是用一组任意的存储单元存放线性表的元素,单链表的存在可以让我们能够在常数时间复杂度内完成查找操作。

image-20210901154018067

单链表的特点

单链表中的每个结点不仅包含值,还包含链接到下一个结点的引用字段。

通过这种方式,单链表将所有节点按顺序组织起来。

与数组不同,我们无法在常量时间内访问单链表中的随即元素。如果我们想要获得第i各元素,必须从头结点逐个遍历。

按索引来访问元素的平均时间复杂度为O(N) N为链表的长度

单链表的操作

单链表结点的定义与设计

struct Node
    {
        int val;      //数据域
        Node* next;   //后继节点
        Node(int newVal):val(newVal),next(nullptr) {}
    };

Node(int newVal):val(newVal),next(nullptr) {}

这一行相当于默认构造函数

为新结点的val数据与赋值为newVal 后继结点默认置为空指针nullptr

操作的设计模式

单链表操作的设计模式是统一的。

一般有一个工作指针和一个累加器作为条件去进行判断和遍历。

在我的代码中你会经常能够看到workNode和count两个变量。

单链表的添加操作

如果想在给定的结点prev之后添加新值,我们应该:

其中 prev–previous 之前 cur-current 当前 next 下一个

1、使用给定值初始化新结点cur

image-20210901154416385

2、将cur的next字段链接到prev的下一个结点next

image-20210901154426244

3、将prev的next字段链接到cur

image-20210901154436282

单链表的删除操作

如果我们想从单链表中删除现有结点cur,分两步

1、找到cur的上一个结点prev及其下一个结点next

image-20210901154602893

2、链接prev到cur的下一个结点next

image-20210901154610878

根据添加和删除操作的设计模式,你应该能够理解其余的算法设计模式!

单链表的设计

单链表类的设计 LinkedList

//手撕单向链表
class LinkedList
{
private:
    struct Node
    {
        int val;      //数据域
        Node* next;   //后继节点
        Node(int newVal):val(newVal),next(nullptr) {}
    };
    Node* head;  //头指针应该置空
    int size;
public:
    LinkedList();
    ~LinkedList();
    void addAtTail(int newVal);  //添加到尾节点之后
    void addAtSomeWhere(int index,int newVal);  //添加到指定位置
    void printList();   //遍历输出链表的所有值
    int get(int index);  //获得指定位置的链表值
    void deleteByIndex(int index); //删除指定位置的元素
    int length(); //返回单向链表的长度  不包含头部节点
    void mySort();   //单向链表排序
};

单链表操作的实现

构造函数

LinkedList::LinkedList()
{
    cout<<"---初始化链表---"<<endl;
    this->head=new Node(1e9);
    this->size++;
}

析构函数

析构函数要删除链表的所有结点

LinkedList::~LinkedList()
{
    Node* workNode=head;
    while(head!=nullptr)
    {
        head=head->next;
        delete workNode;
        workNode=head;
    }
    this->size=0;
}

尾部添加

void LinkedList::addAtTail(int newVal)
{
    //添加到尾节点后面
    Node* workNode=new Node(0);
    Node* newNode=new Node(newVal);
    workNode=head;
    for(int i=0;i<size;i++)
    {
        if(workNode->next!=nullptr)
        {
            workNode=workNode->next;
        }
    }
    workNode->next=newNode;
    this->size++;
}

添加到指定位置

void LinkedList::addAtSomeWhere(int index,int newVal)
{
    //插入元素到指定位置
    Node* workNode=head;    //工作指针 用于游历链表
    int count=0;            //计数器
    while(workNode!=nullptr && count<index-1)
    {
        //定位到传入索引的前一个结点
        workNode=workNode->next;
        count++;
    }
    if(workNode==nullptr)  //如过找不到
    {
        throw "传入索引位置错误";
    }
    else
    {
        Node* newNode=new Node(newVal);
        newNode->next=workNode->next;
        workNode->next=newNode;
    }
}

有没有看到我定义的工作指针和计数累加器?

这就是链表操作的设计模式

找准循环条件 多用while 少用for

先定位到前一个结点 也就是 prev

遍历链表

void LinkedList::printList()
{
    //遍历链表
    Node* workNode=new Node(0);
    workNode=head->next;
    while(workNode!=nullptr)
    {
        cout<<workNode->val<<" ";
        workNode=workNode->next;
    }
    cout<<endl;
}

获得指定位置的元素值

int LinkedList::get(int index)
{
    //获得指定位置的数据
    Node* workNode=head;
    int count=0;  //累加器初始化
    while(workNode!=nullptr && count<index)
    {
        workNode=workNode->next;
        count++;
    }
    if(workNode==nullptr)
    {
        throw "索引错误";
    }
    else
    {
        return workNode->val;
    }
}

删除指定位置的元素

void LinkedList::deleteByIndex(int index)
{
    //删除指定位置的元素
    Node* workNode=head;
    Node* temp=new Node(0);  //存储要被删除的结点
    int count=0;
    while(workNode!=nullptr && count<index-1)
    {
        //定位到前一个结点
        workNode=workNode->next;
        count++;
    }
    if(workNode==nullptr)
    {
        throw "位置错误";
    }
    else
    {
        temp=workNode->next;   //清除内存
        workNode->next=workNode->next->next;
    }
    delete temp;
}

记得要删除结点 清理内存

获得链表长度(不含头结点)

int LinkedList::length()
{
    Node* workNode=head;
    int length=0;
    while(workNode->next!=nullptr)
    {
        workNode=workNode->next;
        length++;
    }
    return length;
}

排序

void LinkedList::mySort()
{
    //排序算法
    //大致思路 先将所有元素存储到vector中 再使用vector的排序算法进行排序
    //遍历链表
    Node* workNode=new Node(0);
    vector<int> v1;
    workNode=head->next;
    while(workNode!=nullptr)
    {
        v1.push_back(workNode->val);
        workNode=workNode->next;
    }
    sort(v1.begin(),v1.end());
    workNode=head->next;
    int count=0;
    while(workNode!=nullptr)
    {
        workNode->val=v1[count];
        workNode=workNode->next;
        count++;
    }
    cout<<v1.size()<<endl;
}

algorithm库内置排序算法

sort(vector.begin(),vector.end());

完整代码

LinkedList.h

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
/*
*Author:YiXing Liu
*Date:2021
*Des:Singly Linked List
*/

//手撕单向链表
class LinkedList
{
private:
    struct Node
    {
        int val;      //数据域
        Node* next;   //后继节点
        Node(int newVal):val(newVal),next(nullptr) {}
    };
    Node* head;  //头指针应该置空
    int size;
public:
    LinkedList();
    ~LinkedList();
    void addAtTail(int newVal);  //添加到尾节点之后
    void addAtSomeWhere(int index,int newVal);  //添加到指定位置
    void printList();   //遍历输出链表的所有值
    int get(int index);  //获得指定位置的链表值
    void deleteByIndex(int index); //删除指定位置的元素
    int length(); //返回单向链表的长度  不包含头部节点
    void mySort();   //单向链表排序
};

LinkedList.cpp

#include "LinkedList.h"

LinkedList::LinkedList()
{
    cout<<"---初始化链表---"<<endl;
    this->head=new Node(1e9);
    this->size++;
}

LinkedList::~LinkedList()
{
    Node* workNode=head;
    while(head!=nullptr)
    {
        head=head->next;
        delete workNode;
        workNode=head;
    }
    this->size=0;
}

void LinkedList::addAtTail(int newVal)
{
    //添加到尾节点后面
    Node* workNode=new Node(0);
    Node* newNode=new Node(newVal);
    workNode=head;
    for(int i=0;i<size;i++)
    {
        if(workNode->next!=nullptr)
        {
            workNode=workNode->next;
        }
    }
    workNode->next=newNode;
    this->size++;
}

void LinkedList::addAtSomeWhere(int index,int newVal)
{
    //插入元素到指定位置
    Node* workNode=head;    //工作指针 用于游历链表
    int count=0;            //计数器
    while(workNode!=nullptr && count<index-1)
    {
        //定位到传入索引的前一个结点
        workNode=workNode->next;
        count++;
    }
    if(workNode==nullptr)
    {
        throw "传入索引位置错误";
    }
    else
    {
        Node* newNode=new Node(newVal);
        newNode->next=workNode->next;
        workNode->next=newNode;
    }
}

void LinkedList::printList()
{
    //遍历链表
    Node* workNode=new Node(0);
    workNode=head->next;
    while(workNode!=nullptr)
    {
        cout<<workNode->val<<" ";
        workNode=workNode->next;
    }
    cout<<endl;
}

int LinkedList::get(int index)
{
    //获得指定位置的数据
    Node* workNode=head;
    int count=0;  //累加器初始化
    while(workNode!=nullptr && count<index)
    {
        workNode=workNode->next;
        count++;
    }
    if(workNode==nullptr)
    {
        throw "索引错误";
    }
    else
    {
        return workNode->val;
    }
}

void LinkedList::deleteByIndex(int index)
{
    //删除指定位置的元素
    Node* workNode=head;
    Node* temp=new Node(0);  //存储要被删除的结点
    int count=0;
    while(workNode!=nullptr && count<index-1)
    {
        //定位到前一个结点
        workNode=workNode->next;
        count++;
    }
    if(workNode==nullptr)
    {
        throw "位置错误";
    }
    else
    {
        temp=workNode->next;   //清除内存
        workNode->next=workNode->next->next;
    }
    delete temp;
}

int LinkedList::length()
{
    Node* workNode=head;
    int length=0;
    while(workNode->next!=nullptr)
    {
        workNode=workNode->next;
        length++;
    }
    return length;
}

void LinkedList::mySort()
{
    //排序算法
    //大致思路 先将所有元素存储到vector中 再使用vector的排序算法进行排序
    //遍历链表
    Node* workNode=new Node(0);
    vector<int> v1;
    workNode=head->next;
    while(workNode!=nullptr)
    {
        v1.push_back(workNode->val);
        workNode=workNode->next;
    }
    sort(v1.begin(),v1.end());
    workNode=head->next;
    int count=0;
    while(workNode!=nullptr)
    {
        workNode->val=v1[count];
        workNode=workNode->next;
        count++;
    }
    cout<<v1.size()<<endl;
}

testList.cpp 测试

#include"LinkedList.h"
using namespace std;

int main()
{
    cout<<"Hello"<<endl;
    cout<<"你好"<<endl;
    LinkedList l1;
    l1.addAtTail(3);
    l1.addAtSomeWhere(2,4);
    l1.addAtTail(8);
    l1.addAtSomeWhere(3,6);
    l1.printList();
    cout<<"长度为"<<l1.length()<<endl;
    cout<<l1.get(2)<<endl;
    l1.deleteByIndex(2);
    l1.addAtSomeWhere(2,9);
    l1.printList();
    cout<<"长度为"<<l1.length()<<endl;
    l1.mySort();
    l1.printList();
    system("pause");
    return 0;
}

image-20210901155639936

后记

测试代码写的不是很详细

你可以自己使用try…catch…去写一下

排序算法写的略复杂

你看看你自己能不能手撕一个链表的冒泡排序出来

防卫式声明也没来得及和你讲

回去教你

谨记

见字如面

勿念

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值