【数据结构】单链表

单链表

结构描述

#include <iostream>
#include <cstdlib>
using namespace std;
typedef int DataType;
//链表节点
typedef struct Node {
DataType A;
struct Node * Next;
}Node;
class SingleLinkedList {
private:
Node * Head;
public:
//尾插
void PushBack(DataType X);
//头插
void PushFront(DataType X);
//在第Pos个位置插入,若不存在该位置报错
void InsertThisPos(int Pos, DataType X);
//尾删
void PopBack();
//头删
void PopFront();
//删除第Pos位元素,若无该位置,则返回错误
void DeleteThisPos(int Pos);
// 把链表置为空表
void MakeEmpty();
//查找值为 Target的元素,若不存在,则返回空指针,存在则返回节点指针
Node * SearchByValue(DataType Target);
void ModifyByValue(DataType Value, DataType NewValue);
//创建一个空表
void Init();
//判空,若空,则返回true,反之返回false
bool IsEmpty();
//打印链表
void Print();
//分配空间,根据参数X分配空间,分配成功则返回该节点的指针
Node * BuyNode(DataType X);
};

初始化

建立一个空表,即把 Head 指向空。

void SingleLinkedList::Init() {
Head = nullptr;
}

判空

判断链表是否为空,即 Head == nullptr 是否成立。

  • 若成立则返回 true

  • 否则返回 false

bool SingleLinkedList::IsEmpty() {
return Head == nullptr;
}

打印

  • 表空:返回错误

  • 非空:从头指针向后遍历,一直遍历到表尾,即Cur == nullptr 时,并打印数据域。

void SingleLinkedList::Print() {
//表空时返回错误
if (IsEmpty()) {
cout << "List Is Empty!\n";
exit(-1);
}
//表非空时遍历链表,并打印每一位元素的值
Node * Cur = Head;
while (Cur != nullptr) {
cout << Cur->A << "\n";
Cur = Cur->Next;
}
}

创建节点

根据参数 X ,创建一个数据域为 X ,指针域为空的节点 NewNode 并返回

Node * SingleLinkedList::BuyNode(DataType X) {
//分配空间,并判断是否成功
Node * NewNode = (Node *)malloc(sizeof (Node));
if (NewNode == nullptr) {
cout << "Malloc Failed!" << "\n";
exit(-1);
}
//给节点赋值
NewNode->A = X;
NewNode->Next = nullptr;
return NewNode;
}

头插

  1. 分配节点 NewNode
  2. 把节点的指针域指向当前头节点,即 NewNode->Next = Head;
  3. 把头指针 Head 指向 NewNode
void SingleLinkedList::PushFront(DataType X) {
Node * NewNode = BuyNode(X);
NewNode->Next = Head;
Head = NewNode;
}

尾插

  • 若表空:
    1. 分配节点;
    2. 把头指针指向该节点;
  • 表非空:
    1. 遍历,找到尾节点
    2. 分配节点,并把节点接在尾节点之后
void SingleLinkedList::PushBack(DataType X) {
//表空
if (IsEmpty()) {
Head = BuyNode(X);
}
//非空
else {
Node * Cur = Head;
//Cur->Next为空时,找到尾节点,退出循环
while (Cur->Next != nullptr) {
Cur = Cur->Next;
}
Node * NewNode = BuyNode(X);
Cur->Next = NewNode;
}
}

头删

  • 表空:报错
  • 非空:
    1. 用临时变量 Tmp 存放头节点;
    2. 把头节点向后移动一位,即 Head = Head->Next;
    3. 释放 Tmp 并置空,防止指针悬空
void SingleLinkedList::PopFront() {
//表空
if (IsEmpty()) {
cout << "List Is Empty!\n";
exit(-1);
}
//非空
Node * Tmp = Head;
Head = Head->Next;
free(Tmp);
Tmp = nullptr;
}

尾删

  • 表空:报错
  • 非空:
    • 只有一个节点:直接置空即可
    • 有多个节点:
      1. 找到倒数第二个节点 Cur
      2. 用临时变量保存尾节点,即 Tmp = Cur->Next
      3. Cur 的指针域指向 nullptr
      4. 释放 Tmp
void SingleLinkedList::PopBack() {
//表为空
if (IsEmpty()) {
cout << "List Is Empty!\n";
exit(-1);
}
//只有一个节点
if (Head->Next == nullptr) {
free(Head);
Head = nullptr;
}
//有两个及以上个节点
else {
Node * Cur = Head;
//找倒数第二个节点
while (Cur->Next->Next != nullptr) {
Cur = Cur->Next;
}
//保存倒数第一个节点
Node * Tmp = Cur->Next;
//把倒数第二个节点指向空指针,Tmp指向尾节点,故其指针域为空指针
Cur->Next = Tmp->Next;
//释放
free(Tmp);
Tmp = nullptr;
}
}

插入元素

Pos 处插入元素(模拟数组下标,从0开始计数)

  • 若存在该位置,则插入元素
    1. Pos 为0,即在链表头插入,直接调用头插方法
    2. Pos 大于0,则遍历链表,循环变量 i1 开始,考虑下标为 1 到尾的节点
    3. Pre 变量存放 第 i - 1 号位的节点指针,循环条件为 i < Pos && Pre != nullptr,如果 Pre 为空,即指向了链表的最后,若此时 i != Pos ,则下存在,返回错误
    4. i == Pos,则该位置存在,直接分配节点并插入即可 。有点双指针的意思
  • 不存在该位置,则返回错误;
void SingleLinkedList::InsertThisPos(int Pos, DataType X) {
if (Pos == 0) {
PushFront(X);
}
else {
int i;
Node * Pre;
for (i = 1, Pre = Head; i < Pos && Pre != nullptr; i++, Pre = Pre->Next) {
;
}
//退出循环时,不是i == Pos, 就是 Pre == nullptr
if (Pos == i && Pre != nullptr) {
Node * NewNode = BuyNode(X);
NewNode->Next = Pre->Next;
Pre->Next = NewNode;
}
else {
cout << Pos << " Posiont is not exist!\n";
exit(-1);
}
}
}

删除元素

  • 表空:报错
  • 非空:
    • 删除第0个元素时,直接调用头删方法
    • 有多个元素时:
      1. 和插入一样,用一个 Pre 指针指向要删除元素的前一位,即 Pre = Head, i = 1
      2. 遍历链表,直至 i == Pos || Pre->Next == nullptr 时退出循环,Pre->Next == nullptr时,说明要删除的元素是尾指针的指针域,即空指针,这显然是错误的,所以可以以此来作为遍历的出口条件
      3. 若第 Pos 个元素存在,则删除该元素
void SingleLinkedList::DeleteThisPos(int Pos) {
//判空
if (IsEmpty()) {
cout << "List Is Empty!\n";
exit(-1);
}
//非空,删除第0个元素
if (Pos == 0) {
PopFront();
}
else {
//非空,删除第N个元素(N > 0)
int i = 0;
Node * Pre = nullptr;
for (i = 1, Pre = Head; Pre->Next != nullptr && i < Pos; i++, Pre = Pre->Next) {
;
}
if (i == Pos && Pre->Next != nullptr) {
Node * Tmp = Pre->Next;
Pre->Next = Tmp->Next;
free(Tmp);
Tmp = nullptr;
}
else {
cout << Pos << " Position is not exist!\n";
}
}
}

根据值查找元素

  • 表空:返回错误
  • 非空:遍历链表,逐一比较,直到第一个与目标值相等的元素时,返回该节点的指针。若直至表尾仍未发现该元素,则返回一个空指针。
Node * SingleLinkedList::SearchByValue(DataType Target) {
if (IsEmpty()) {
cout << "List Is Empty!\n";
exit(-1);
}
Node * Cur = Head;
while (Cur != nullptr) {
if (Cur->A == Target) {
return Cur;
}
Cur = Cur->Next;
}
return nullptr;
}

修改链表元素值

  • 查找:
    • 表空:返回错误
    • 非空:找到返回,找不到返回空
  • 修改:根据查找到的结果修改;
    • 查找返回空:给出提示消息,并退出程序
    • 查找返回元素节点指针:修改该元素的值
void SingleLinkedList::ModifyByValue(DataType Target, DataType NewValue) {
Node * Ret = SearchByValue(Target);
if (Ret == nullptr) {
cout << "The Target Is Not Exist!\n";
exit(-1);
}
Ret->A = NewValue;
}

摧毁

  • 表空:返回错误
  • 不空:一直头删,直至表空
void SingleLinkedList::MakeEmpty() {
if (IsEmpty()) {
cout << "List Is Empty!\n";
exit(-1);
}
while (!IsEmpty()) {
PopFront();
}
}
posted @   codels  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示