C++实现单链表【每一步详细深入讲解,代码清晰、简单、易懂】

本文详细介绍了单链表的基本操作,包括插入、删除和查找等,并提供了完整的代码实现。此外,还对比了循环链表与普通单链表的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、单链表的结构(以数据为不重复整数为例)

0、overview

链表元素由数据和指针构成,因此链表的节点可以由一个包含这两种元素的结构体代表:

// 单链表节点
struct SingleListNode {
    int data;
    SingleListNode* next;
    SingleListNode(int val, SingleListNode* ptr = nullptr);
};

链表包含插入、删除操作,而插入、删除又必须先查找元素是否存在,因此查找方法也必不可少。

//单链表
class SingleList {
public:
    SingleListNode* dummy;
    SingleList();
    ~SingleList();
public:
    void add(int);
    void remove(int);
    SingleListNode* find(int);
};

1、插入操作

在这里插入图片描述

例如:我们需要在伪头节点(不包含数据)和含有1的节点之间插入一个节点,发现,只需要改变dummy的指针和需要插入的指针即可。那么很容易想到下面的步骤:

  • 将dummy的指针指向要添加的节点

  • 将要添加节点的指针指向之前的下一个节点

这样我们就添加了一个节点。

但是发现了一个问题:因为单向链表只能通过前一个的指针寻找下一个元素,如果该指针指向改变了,我们就永远也找不到下一个元素了,因此,上面步骤2是错误的。那我们应该如何添加元素?

正确的添加顺序

  • 先将要添加的元素的指针指向dummy节点的后一个节点

  • 再将dummy节点的指针指向要添加的节点

插入的情况讨论

  • 插入时这里为了方便统一在dummy节点之后插入,也即每次插入一个新元素都在开头插入

图例:

初始插入2插入3

插入的代码逻辑

  • 读取find函数返回值判读元素是否已存在
  • 存在则输出插入失败,并返回
  • 不存在则执行插入操作
void SingleList::add(int val) {
    auto ptr = find(val);
    if (ptr) {
        std::cerr << val << " exists, add failed!" << std::endl;
        return;
    } else {
        auto temp = new SingleListNode(val);
        temp->next = dummy->next;
        dummy->next = temp;
    }
}

2、删除操作

相比于插入,删除要简单一些

例如我们要删除上图包含2的节点,只需执行下面的步骤

  • 将需要删除的节点的前一个节点的指针指向需要删除的节点的下一个节点,也即dummy的节点指向1
  • 再将需要删除的节点释放掉

删除的代码逻辑

  • 读取find函数的返回值判断元素是否存在
  • 不存在则输出错误提示并返回
  • 存在则执行删除操操作
void SingleList::remove(int val) {
    auto ptr = find(val);
    if (ptr == nullptr) {
        std::cerr << val << " does not exist, remove failed!" << std::endl;
        return;
    } else {
        auto temp = ptr->next;
        ptr->next = ptr->next->next;
        delete temp;
    }
}

3、查找操作

通过对插入和删除的讨论,我们了解到,插入调用find函数时,并不需要操作其返回值,所以,返回值具体是该元素的节点还是其前面的节点并没有影响;但是,由于单链表只能通过前一个的指针寻找下一个元素,因此,删除操作时我们必须得到需要删除节点的前一个节点,因此find的返回值必须设为需要寻找的节点的前一个节点,而第一个节点的前一个节点是dummy,这也是我们需要dummy这个伪头节点的原因之一。

查找代码的逻辑

  • 从第一个含有元素的节点开始寻找,依次向后
  • 如果找到该节点,则返回之
  • 如果链表遍历完也没有找到,就返回nullptr
SingleListNode* SingleList::find(int val) {
    auto prev = dummy;
    auto temp = dummy->next;
    while (temp) {
        if (temp->data == val)
            return prev;
        prev = prev->next;
        temp = temp->next;
    }
    return nullptr;
}

循环链表的查找

当单链表为循环链表时,最后一个元素的next指针不是指向nullptr,而是dummy节点,因此,查找代码有一些小变化,同时构造、析构以及测试代码都围绕dummy的next指针有相应的小变化(详见代码)

SingleListNode* SingleList::find(int val) {
    auto prev = dummy;
    auto temp = dummy->next;
    while (temp != dummy) {	//循环条件变为temp不等于dummy
        if (temp->data == val)
            return prev;
        prev = prev->next;
        temp = temp->next;
    }
    return nullptr;
}

4、完整代码

// SingleList.h 单链表类定义

// 单链表节点
struct SingleListNode {
    int data;
    SingleListNode* next;
    SingleListNode(int val, SingleListNode* ptr = nullptr);
};

//单链表
class SingleList {
public:
    SingleListNode* dummy;
    SingleList();
    ~SingleList();
public:
    void add(int);
    void remove(int);
    SingleListNode* find(int);
};
// SingleList.cpp 单链表类的函数实现及静态成员定义
#include <iostream>
#include "SingleList.h"

SingleListNode::SingleListNode(int val, SingleListNode* ptr)
    : data(val), next(ptr) { }

SingleList::SingleList() : dummy(new SingleListNode(-1)) { }

SingleList::~SingleList() {
    auto ptr = dummy->next;
    while (ptr) {
        auto temp = ptr;
        ptr = ptr->next;
        delete temp;
        std::cout << "Element deleted!" << std::endl;
    }
    delete dummy;
    std::cout << "SingleList Destroyed!" << std::endl;
}

void SingleList::add(int val) {
    auto ptr = find(val);
    if (ptr) {
        std::cerr << val << " exists, add failed!" << std::endl;
        return;
    } else {
        auto temp = new SingleListNode(val);
        temp->next = dummy->next;
        dummy->next = temp;
    }
}

void SingleList::remove(int val) {
    auto ptr = find(val);
    if (ptr == nullptr) {
        std::cerr << val << " does not exist, remove failed!" << std::endl;
        return;
    } else {
        auto temp = ptr->next;
        ptr->next = ptr->next->next;
        delete temp;
    }
}

SingleListNode* SingleList::find(int val) {
    auto prev = dummy;
    auto temp = dummy->next;
    while (temp) {
        if (temp->data == val)
            return prev;
        prev = prev->next;
        temp = temp->next;
    }
    return nullptr;
}
// SingleListTest.cpp 对该单链表的测试代码

#include <iostream>
#include "SingleList.h"

int main(void) {
	SingleList list;

	list.add(0);
	list.add(1);
	list.add(2);
	list.add(3);
	list.add(4);
	list.add(4);	// 添加已存在元素
	list.remove(0); // 末尾元素
	list.remove(2); // 中间元素
	list.remove(4); // 开头元素
	list.remove(4); // 删除不存在元素
	for (auto temp = list.dummy->next; temp; temp = temp->next)
		std::cout << temp->data << " ";
	std::cout << std::endl;
	/*期望的输出
	4 exists, add failed!
	4 does not exist, remove failed!
	3 1
	Element deleted!
	Element deleted!
	SingleList Destroyed!
	*/
	return 0;
}

5、循环链表的代码

链表的结构仅有查找函数有变化同时,测试的代码也有相应的变化

// SingleList.h 单循环链表类定义

// 单循环链表节点
struct SingleListNode {
    int data;
    SingleListNode* next;
    SingleListNode(int val, SingleListNode* ptr = nullptr);
};

//单循环链表
class SingleList {
public:
    SingleListNode* dummy;
    SingleList();
    ~SingleList();
public:
    void add(int);
    void remove(int);
    SingleListNode* find(int);
};
// SingleList.cpp 单循环链表类的函数实现及静态成员定义
#include <iostream>
#include "SingleList.h"

SingleListNode::SingleListNode(int val, SingleListNode* ptr)
    : data(val), next(ptr) { }

SingleList::SingleList() 
    : dummy(new SingleListNode(-1)) { // 构造dummy时,需要把next指向本身
    dummy->next = dummy; 
}

SingleList::~SingleList() {
    auto ptr = dummy->next;
    while (ptr != dummy) { // 析构条件变为ptr != dummy
        auto temp = ptr;
        ptr = ptr->next;
        delete temp;
        std::cout << "Element deleted!" << std::endl;
    }
    delete dummy;
    std::cout << "SingleList Destroyed!" << std::endl;
}

void SingleList::add(int val) {
    auto ptr = find(val);
    if (ptr) {
        std::cerr << val << " exists, add failed!" << std::endl;
        return;
    } else {
        auto temp = new SingleListNode(val);
        temp->next = dummy->next;
        dummy->next = temp;
    }
}

void SingleList::remove(int val) {
    auto ptr = find(val);
    if (ptr == nullptr) {
        std::cerr << val << " does not exist, remove failed!" << std::endl;
        return;
    } else {
        auto temp = ptr->next;
        ptr->next = ptr->next->next;
        delete temp;
    }
}

SingleListNode* SingleList::find(int val) {
    auto prev = dummy;
    auto temp = dummy->next;
    while (temp != dummy) { //循环条件变为temp不等于dummy
        if (temp->data == val)
            return prev;
        prev = prev->next;
        temp = temp->next;
    }
    return nullptr;
}
// SingleListTest.cpp 对该单循环链表的测试代码

#include <iostream>
#include "SingleList.h"

int main(void) {
	SingleList list;

	list.add(0);
	list.add(1);
	list.add(2);
	list.add(3);
	list.add(4);
	list.add(4);	// 添加已存在元素
	list.remove(0); // 末尾元素
	list.remove(2); // 中间元素
	list.remove(4); // 开头元素
	list.remove(4); // 删除不存在元素
	for (auto temp = list.dummy->next; temp != list.dummy; temp = temp->next) // 循环链表循环条件为temp != list.dummy
		std::cout << temp->data << " ";
	std::cout << std::endl;
	/*期望的输出
	4 exists, add failed!
	4 does not exist, remove failed!
	3 1
	Element deleted!
	Element deleted!
	SingleList Destroyed!
	*/
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值