c++实现双向链表类(增,删,改,查)

前言

小猿根据实际需求,此次实现的是双向链表类,并附有详细的代码注释,双向链表是工作最实用的数据结构类型,和小猿一起学习吧。

一、链表的特点及和数组的区别

特点:
1、 链表是一种非连续的存储结构(相对于数组)。
2、 链表由一系列的结点组成,每个结点包括两个部分:数据和指针。
3、 链表通过结点中的指针来确定逻辑顺序。
区别:
1、 数组通过数组名字以及[]中的下标来访问数据,链表通过指针找到数据。
2、 数组无法动态增删元素(只能改),链表可以动态增、删、改结点。
3、 数组的定义、使用和回收空间操作简单,链表以上都复杂。
因此,在已知所存储数据的总数,且需要快速查找,一般用数组;存储数据需要经常增、删,一般用链表,实际工作中链表的使用范围更广。

二、具体实现

1.定义类

1.1结点类

//结点类
class Node
{
public:
    string ip;//客户端ip
    string name;//客户端名字
    Node *next;//指向下一个结点
    Node *prev;//指向上一个结点
    int len;
    Node()
    {
        //当前对象不用加前缀
        next = nullptr;
        prev = nullptr;
    }
    void display()
    {
        cout << ip <<" "<< name << endl;
    }
};

因为NULL也可以表示为零,而int *p 和p = NULL可能没连在一起;所以为了明确表示空指针,c++11版本以后用nullptr, 不能赋值整型,严格限制只能赋值指针,便于程序员区分。

1.2链表类

class MYList
{
public:
	//头结点
    Node *head;
    MYList();
    ~MYList();
    //增加一个结点
    void addMYList(string,string);
    //删除一个结点
    void deleteMYList(string);
    //修改一个结点
    void modifyMYList(string,string);
    //遍历链表
    void traverse();
};

2.链表类的构造函数与析构函数

MYList::MYList()
{
    //新建一个头结点
    head = new Node();
    //Node = new Node;堆空间都一样
    // Node n;栈空间正确写法 ;Node n ();栈空间这样写错误,意思不一样
    head->len = 0;
}
MYList::~MYList()
{
    Node* p = head;
    //伴随指针
    Node* q = head;
    while(p)
    {
        q->next = p->next;
        delete p;
        //delete p之后,p是一个无意义的值,无法操作p->next,p->prev
        p = q->next;
    }
}

3.增

//增加一个结点
void MYList::addMYList(string ip,string name)
{
    //创建数据结点
    Node* pnew = new Node();
    if(pnew == nullptr)
        return ;
    pnew->ip = ip;
    pnew->name = name;
    //头插
    //数据结点插在头结点后面(数据结点从无到有)
    if(head->next == nullptr)
    {
        pnew->next = head->next;
        pnew->prev = head;
        head->next = pnew;
        //记录结点个数
        head->len++;
    }
    //从少到多
    else
    {
        pnew->next = head->next;
        pnew->prev = head;
        head->next->prev = pnew;
        head->next = pnew;
        head->len++;
    }
}

4.删

//根据客户端ip删除
void MYList::deleteMYList(string ip)
{
   //p指向第一个数据结点
	Node* p = head->next;
	//Node* q = head->next;
	//遍历
	while(p)
	{
		if(p->ip == ip)
        {
            //只有一个数据结点
            if(p->next == nullptr)
            {
                p->prev->next = NULL;
                p->prev = NULL;
            }
            //多个
            else
            {
                p->prev->next = p->next;
                p->next->prev = p->prev;
                p->next = nullptr;
                p->prev = nullptr;
            }
            delete p
            head->len--;
            //ip唯一
            break ;
            //ip不唯一,需要伴随指针q
            //p = q->next
        }
		else
		p = p->next;
		//q = q->next;
	}
}

5.改

//根据ip修改名字
void MYList::modifyMYList(string ip,string name)
{
	//p指向第一个数据结点
	Node* p = head->next;
	//遍历
	while(p)
	{
		if(p->ip == ip)
        {
            //name形参
            p->name = name;
        }
		else
		p = p->next;
	}
}

6.查

//遍历打印函数
void MYList::traverse()
{
    Node* p = head->next;
    if(p == nullptr)
        return ;
    //遍历
    while(p)
    {
        //结点类打印方法
        p->display();
        p = p->next;
    }
}

7.测试及结果

int main()
{
    MYList h;
    h.addMYList("2020","新能源汽车");
    h.addMYList("2050","移民火星");
    h.addMYList("2040","脑机接口");
    h.addMYList("0000","马斯克");
    h.traverse();
    cout << h.head->len<<endl;
    
    h.deleteMYList("0000");
    h.traverse();
    
    h.deleteMYList("2020");
    cout << h.head->len<<endl;
    
    h.modifyMYList("2050","飞向太阳");
    h.traverse();
    
    h.deleteMYList("2050");
    h.deleteMYList("2040");
    h.traverse();
    cout << h.head->len<<endl;
    return 0;
}

在这里插入图片描述

总结

实现链表类的时候需要注意单向链、双向链、循环链的不同情况,最好构建类模板。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值