c++类模拟实现单向链表

c++类模拟实现单向链表

本次使用c++中的类的语法来模拟实现单向链表,单向链表结构较为简单,一个节点中只存储数据和下一个节点的指针,本次实现仍然带有哨兵位头节点

本次实现的接口有增删展示与销毁,查改读者可作为练习自行模拟实现
以下是本次使用的节点结构体与类和其中成员函数和成员变量

#include<iostream>
#include<cstdlib>
#include<cassert>
using namespace std;
typedef int LLtype;
struct List
{
    LLtype x;
    List* next;
};
class list
{
    private:
    List*head;
    //创建一个新节点
    List* Create_Node(LLtype x);
    //销毁链表
    void delt();
    public:
    //默认构造函数
    list();
    //有参构造函数
    list(List*head);
    //头插
    void push_front(LLtype x);
    //尾插
    void push_back(LLtype x);
    //展示链表
    void Show();
    //头删
    void pop_front();
    //尾删
    void pop_back();
    //析构函数
    ~list();
};

本次模拟实现会使用到assert进行报错判断,包含了cassert头文件

1.对于private成员的设置,目的是不在类外进行访问,尽量通过提供的public成员进行操作

2.默认构造函数

创建类之初会自动调用的默认构造函数,我们在这里对其进行的操作是将head指针赋值为NULL

list()
    {
        head=NULL;
    }

3.有参构造函数

使用有参构造函数是为了对类进行初始化,给head赋值为我们在main函数中使用malloc开辟的一块空间

//有参构造函数
    list(List*head)
    {
        this->head=head;
        this->head->next=NULL;
    }

4.创建一个节点

在增添元素时我们都会创建一个新节点,将其写为一个函数方便复用

//创建一个新节点
    List* Create_Node(LLtype x)
    {
        List*newnode=(List*)malloc(sizeof(List));
        newnode->x=x;
        newnode->next=NULL;
        return newnode;
    }

返回结构体指针在函数内使用对应指针进行接受即可

5.头插

void push_front(LLtype x)
    {
        assert(this->head);
        List*newnode=Create_Node(x);
        List*next=head->next;
        head->next=newnode;
        newnode->next=next;
    }

这里使用了assert对head进行断言,head作为哨兵位头节点是一定不能为空指针的
接下来改变对应链接关系即可,同样的有哨兵位头节点的存在,无需对新的实际头节点进行操作,关于改变对应连接关系可参考上一篇双链表的实现有详细说明

6.尾插

void push_back(LLtype x)
    {
        assert(this->head);
        List*tail=head;
        while(tail->next)
        tail=tail->next;
        List*newnode=Create_Node(x);
        tail->next=newnode;
    }

同样的,找到尾之后进行链接关系的改变即可

7.展示链表

//展示链表
    void Show()
    {
        List*cur=head->next;
        while(cur)
        {
            cout<<cur->x<<"->";
            cur=cur->next;
        }
        cout<<"NULL"<<endl;
    }

head指针作为哨兵位头节点不存储实际数据,从head->next开始进行遍历输出

8.头删

//头删
    void pop_front()
    {
        assert(this->head);
        assert(this->head->next);
        List*next=head->next->next;
        free(head->next);
        head->next=next;
    }

头删删的时哨兵位头节点的下一个,所以head不能为空,同样的链表内要有元素才能删除,所以head->next也不能为空,所以对二者都进行断言,注意存储下一个节点的指针,这样free掉原先实际头节点后仍有新的头节点的指针,接着改变链接关系即可

9.尾删

//尾删
    void pop_back()
    {
        assert(this->head);
        assert(this->head->next);
        List*tail=head->next;
        List*prev=NULL;
        while(tail->next)
        {
            prev=tail;
            tail=tail->next;
        }
        free(tail);
        prev->next=NULL;
    }

与头删类似,存储尾节点的前一个节点,新的尾节点要置空,同样的,哨兵位头节点不能为空,实际头节点也不能为空才有元素可以删除

10.销毁链表函数

注意这里是说他是销毁链表函数,是因为我们只写他,而不调用他,调用他的操作交给编译器完成(即析构函数)

void delt()
    {
        List*next=NULL;
        List*cur=head->next;
        while(cur)
        {
            next=cur->next;
            free(cur);
            cur=next;
        }
        free(head);
    }

同样的,把他写在private作用域下是不希望在类外调用该函数

11.析构函数

~list()
    {
        delt();
    }

在析构函数中我们直接调用刚刚完成的delt函数对链表进行销毁,这是因为编译器会在程序结束后调用析构函数,这样即释放了malloc出的空间,也在一个合适的时机对链表进行销毁而且是一定会销毁,避免了内存泄漏的问题
本次实现的接口就这么多,在类内实现便于我们对成员函数的调用,是一种非常便利的操作,读者也可尝试使用类进行双向循环链表的模拟,这也是c++STL中list容器中的链表的原理
最后感谢大家的阅读,欢迎各位读者批评指错

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值