【C++】单链表——单链表的基本操作

news2024/11/20 10:43:51

1、单链表的定义

 由于顺序表的插入删除操作需要移动大量的元素,影响了运行效率,因此引入了线性表的链式存储——单链表。单链表通过一组任意的存储单元来存储线性表中的数据元素,不需要使用地址连续的存储单元,因此它不要求在逻辑上相邻的两个元素在物理位置上也相邻。

单链表的特点:

  • 单链表不要求逻辑上相邻的两个元素在物理位置上也相邻,因此不需要连续的存储空间
  • 单链表是非随机的存储结构,即不能直接找到表中某个特定的结点。查找某个特定的结点时,需要从表头开始遍历,依次查找。

优点:

  • 支持动态内存分配。由于单链表不需要预先分配一段连续的空间,因此可以根据实际需求动态地申请、释放节点空间,避免浪费内存。
  • 支持高效的插入、删除操作。由于单链表中的节点是通过指针相连的,因此在插入、删除一个节点时,只需要修改其前驱节点或后继节点的指针即可,时间复杂度为O ( 1 ) 。
     

 缺点:

  • 不支持随机访问。由于单链表中的节点不是连续存储的,因此不能像数组一样通过下标来直接访问一个元素,需要从头节点开始遍历整个链表才能访问任意位置的元素。

 创建一个类

template <class T>								// T为单链表存储的元素类型
class linkList
{
private:
    struct Node
    {
    public:
        T  data;								  // 结点的数据域 
        Node* next;								  // 结点的指针域,指向后继结点 
        Node(const T value, Node* p = NULL)       // 具有两个参数的Node构造函数 
        {	
            data = value;
            next = p;
        }
        Node(Node* p = NULL)                      // 具有一个参数的Node构造函数  
        { 						
            next = p;
        }
    };


    Node* head;								// 单链表的头指针 
    Node* tail;    							// 单链表的尾
    int curLength;							// 单链表的当前长度
    Node* getPosition(int i)const;			// 返回指向单链表中第i个元素的指针     

public:
    linkList();								    // 构造函数 
    ~linkList();								// 析构函数  
    void clear(); 								// 将单链表清空,使之成为空表
    bool empty()const;                          // 判空
    int size();                                 // 返回单链表的当前实际长度  						 
    void insert(int i, const T& value);	        // 在位置i上插入一个元素value,表的长度增1
    void remove(int i);							// 删除位置i上的元素value,若删除位置合法,表的长度减1 
    int search(const T& value)const;		    // 查找值为value的元素第一次出现的位序
    T visit(int i)const;					    // 访问位序为i的元素值,“位序”0表示第一个元素,类似于数组下标
    void traverse()const;						// 遍历单链表	
    void headCreate();							// “头插法”
    void tailCreate();							// “尾插法”
    void inverse();								// 逆置单链表
    int prior(const T& value)const;		        // 查找值为value的元素的前驱

};

 2、单链表的初始化

  • 通常会用头指针来标识一个单链表,头指针为nullptr时表示一个空表。
  • 但是,为了操作方便,会在单链表的第一个结点之前附加一个结点,称为头结点
  • 头结点的数据域可以不设任何信息,也可以记录表长等信息。

 

代码实现: 

template <class T>
linkList<T>::linkList()
{
    head = tail = new Node();				    // 创建带有头结点的空表
    curLength = 0;
}

 3、单链表的建立

3.1、头插法建立单链表

头插法建立单链表是说将新结点插入到当前链表的表头,即头结点之后。

思路:输入一个结束标志flag,使用一个while循环,判断条件是 value != flag

代码实现:

template <class T>  						// 头插法创建 
void linkList<T>::headCreate()
{
    Node* p;
    T value, flag;
    cin >> flag;									// 输入结束标志

    cin >> value;
    while (value != flag)
    {
        p = new Node(value);
        p->next = head->next;
        head->next = p;
        curLength++;
        cin >> value;
    }
}

3.2、尾插法建立单链表

尾插法建立单链表,就是将新结点插入到当前链表的表尾。

代码实现:

template <class T>  						// 尾插法创建链表
void linkList<T> ::tailCreate()
{
    Node* p;
    T value, flag;
    cin >> flag;									// 输入结束标志

    cin >> value;
    while (value != flag)
    {
        p = new Node(value);
        tail->next = p;
        tail = p;
        curLength++;
        cin >> value;
    }

}

4、单链表的遍历 

代码实现:

template <class T>
void  linkList<T> ::traverse()const
{
    Node* p = head->next;
    while (p != nullptr)
    {
        cout << p->data << "  ";
        p = p->next;
    }
    cout << endl;
 
}

5、单链表的长度

代码实现:

template <class T>
int linkList<T>::size()
{ 
    return curLength; 
}

6、单链表的查找

6.1、按值查找

代码实现:

template <class T>
int linkList<T> ::search(const T& value)const
{
    Node* current = head->next;
    int i = 0;
    while (current != nullptr)
    {
        if (current->data == value)
        {
            break;
        }
        else
        {
            current = current->next;
            i++;
        }
    }
    if (current != nullptr)
    {
        return i;
    }
    return -1;


}

6.2、按位查找

代码实现:

template <class T>  						// 访问位序为i的元素返回其数据域
T linkList<T> ::visit(int i)const 
{

    if (i < 0 || i>(curLength - 1))
    {
        T a = 0;
        return a;
    }
    Node* current = head->next;
    while (i--)
    {
        current = current->next;
    }

    return current->data;
 
}

7、单链表的插入

返回指向单链表中第i个元素的指针

template <class T>
typename linkList<T> ::Node* linkList<T> ::getPosition(int i)const
{
    Node* ptemp = head;
    int k = 0;
    while (k < i)
    {
        ptemp = ptemp->next;
        k++;
    }
    return ptemp;
}

代码实现:

template  <class T>
void linkList<T> ::insert(int i, const T& value)
{
    Node* current = getPosition(i);
    Node* newNode = new Node(value);
    newNode->next = current->next;
    current->next = newNode;
    curLength++;

}

8、单链表的删除

代码实现:

template  <class T>
void  linkList<T>::remove(int i)
{

    Node* current = getPosition(i);
    Node* del = current->next;
    current->next = del->next;
    delete del;
    curLength--;
 
}

9、单链表的判空

代码实现:

template <class T>
bool linkList<T>::empty()const
{
    return head->next == nullptr;
}

总代码实现:

#include<stack>


template <class T>								// T为单链表存储的元素类型
class linkList
{
private:
    struct Node
    {
    public:
        T  data;								  // 结点的数据域 
        Node* next;								  // 结点的指针域,指向后继结点 
        Node(const T value, Node* p = NULL)       // 具有两个参数的Node构造函数 
        {	
            data = value;
            next = p;
        }
        Node(Node* p = NULL)                      // 具有一个参数的Node构造函数  
        { 						
            next = p;
        }
    };


    Node* head;								// 单链表的头指针 
    Node* tail;    							// 单链表的尾
    int curLength;							// 单链表的当前长度
    Node* getPosition(int i)const;			// 返回指向单链表中第i个元素的指针     

public:
    linkList();								    // 构造函数 
    ~linkList();								// 析构函数  
    void clear(); 								// 将单链表清空,使之成为空表
    bool empty()const;                          // 判空
    int size();                                 // 返回单链表的当前实际长度  						 
    void insert(int i, const T& value);	        // 在位置i上插入一个元素value,表的长度增1
    void remove(int i);							// 删除位置i上的元素value,若删除位置合法,表的长度减1 
    int search(const T& value)const;		    // 查找值为value的元素第一次出现的位序
    T visit(int i)const;					    // 访问位序为i的元素值,“位序”0表示第一个元素,类似于数组下标
    void traverse()const;						// 遍历单链表	
    void headCreate();							// “头插法”
    void tailCreate();							// “尾插法”
    void inverse();								// 逆置单链表
    int prior(const T& value)const;		        // 查找值为value的元素的前驱

};

template <class T>
linkList<T>::linkList()
{
    head = tail = new Node();				    // 创建带有头结点的空表
    curLength = 0;
}

template <class T>
linkList<T>::~linkList()
{
    clear();
    delete head;								// 删除头结点
}

template <class T>
bool linkList<T>::empty()const
{
    return head->next == nullptr;
}

template <class T>
int linkList<T>::size()
{ 
    return curLength; 
}

template <class T>
void linkList<T>::clear()
{

    Node* p = head->next;
    while (p)
    {
        head = head->next;
        delete p;
        p = head;
    }

}

template <class T>
typename linkList<T> ::Node* linkList<T> ::getPosition(int i)const
{
    Node* ptemp = head;
    int k = 0;
    while (k < i)
    {
        ptemp = ptemp->next;
        k++;
    }
    return ptemp;
}


template  <class T>
void linkList<T> ::insert(int i, const T& value)
{
    Node* current = getPosition(i);
    Node* newNode = new Node(value);
    newNode->next = current->next;
    current->next = newNode;
    curLength++;

}

template  <class T>
void  linkList<T>::remove(int i)
{

    Node* current = getPosition(i);
    Node* del = current->next;
    current->next = del->next;
    delete del;
    curLength--;
  

}

template <class T>
void  linkList<T> ::traverse()const
{
    Node* p = head->next;
    while (p != nullptr)
    {
        cout << p->data << "  ";
        p = p->next;
    }
    cout << endl;
 
}

template <class T>
int linkList<T> ::search(const T& value)const
{


    Node* current = head->next;
    int i = 0;
    while (current != nullptr)
    {
        if (current->data == value)
        {
            break;
        }
        else
        {
            current = current->next;
            i++;
        }
    }
    if (current != nullptr)
    {
        return i;
    }
    return -1;


}

template <class T>  						// 访问位序为i的元素返回其数据域
T linkList<T> ::visit(int i)const 
{

    if (i < 0 || i>(curLength - 1))
    {
        T a = 0;
        return a;
    }
    Node* current = head->next;
    while (i--)
    {
        current = current->next;
    }

    return current->data;
 
}

template <class T>  						// 头插法创建 
void linkList<T>::headCreate()
{
    Node* p;
    T value, flag;
    cin >> flag;									// 输入结束标志

    cin >> value;
    while (value != flag)
    {
        p = new Node(value);
        p->next = head->next;
        head->next = p;
        curLength++;
        cin >> value;
    }
}

 

template <class T>  						// 尾插法创建链表
void linkList<T> ::tailCreate()
{
    Node* p;
    T value, flag;
    cin >> flag;									// 输入结束标志

    cin >> value;
    while (value != flag)
    {
        p = new Node(value);
        tail->next = p;
        tail = p;
        curLength++;
        cin >> value;
    }

}
template <class T>  						// 头插法逆置   
void linkList<T> ::inverse()
{

    Node* temp = nullptr;
    Node* p = head->next;
    head->next = nullptr;
    while (p != nullptr)
    {
        temp = p;
        p = p->next;
        temp->next = head->next;
        head->next = temp;
    }

}

template <class T>
int linkList<T> ::prior(const T& value)const
{
    Node* current = head->next;
    int a = 0;
    Node* p = nullptr;
    while (current != nullptr)
    {
        if (current->data == value)
        {
            break;
        }
        else
        {
            current = current->next;
            a++;
        }
    }
    if (current != nullptr)
    {
        return a - 1;
    }
    return -1;

}

执行

#include<iostream>
using namespace std;


#include"SList.h"



int main()
{
	linkList<int>* lk1, * lk2;
	lk1 = new linkList<int>();
	lk2 = new linkList<int>();
	int i;
	int val;
	lk1->headCreate();          // 测试头插法创建单链表
	lk2->tailCreate();          // 测试尾插法创建单链表 
	lk1->traverse();           // 测试遍历
	lk2->traverse();           // 测试遍历
	
	cout << "查找值为2的位序:" << lk1->search(2) << endl;
	cout << "查找位序为2的值" << lk1->visit(2) << endl;
	cout << "长度:" << lk1->size();
	return 0;
}

执行结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1269522.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mysq8l在Centos上安装后忘记root密码如何重新设置

场景 Mysql8在Windows上离线安装时忘记root密码&#xff1a; Mysql8在Windows上离线安装时忘记root密码-CSDN博客 如果是在Windows上忘记密码可以参考上面。 如果在Centos中安装mysql可以参考下面。 CentOS7中安装Mysql8并配置远程连接和修改密码等&#xff1a; CentOS7中…

【知识】稀疏矩阵是否比密集矩阵更高效?

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 问题提出 有些地方说&#xff0c;稀疏图比密集图的计算效率更高&#xff0c;真的吗&#xff1f; 原因猜想 这里的效率高&#xff0c;应该是有前提的&#xff1a;当使用稀疏矩阵的存储格式(如CSR)时&#xff0c;计…

使用 Docker 安装和配置 MySQL 数据库简介

目录 一、使用镜像安装 1、查询镜像 2、拉取镜像 3、查看本地镜像 4、启动docker镜像 二、使用Docker Compose安装 1、安装Docker和Docker Compose 2、创建Docker Compose文件&#xff1a; 3、启动MySQL容器 4、验证MySQL容器是否正常运行 5、连接到MySQL容器 6、停止…

适用于 Windows 的最佳电脑数据恢复软件是什么?

数据丢失是数字世界中令人不快的一部分&#xff0c;它会在某一时刻影响许多计算机用户。很容易意外删除一些重要文件&#xff0c;这可能会在您努力恢复它们时带来不必要的压力。幸运的是&#xff0c;数据恢复软件可以帮助恢复已删除的文件&#xff0c;即使您没有备份它们。这是…

【IEEE独立出版】2024第四届神经网络、信息与通信工程国际学术会议(NNICE 2024)

2024第四届神经网络、信息与通信工程国际学术会议&#xff08;NNICE 2024&#xff09; 2024 4th International Conference on Neural Networks, Information and Communication Engineering 2024第四神经网络、信息与通信工程国际学术会议&#xff08;NNICE 2024&#xff0…

Halcon Solution Guide I basics(5): 1D Measuring(一维测距)

文章专栏 我的Halcon开发 CSDN 专栏 Halcon学习 练习项目gitee仓库 CSDN Major 博主Halcon文章推荐 随笔分类 - Halcon入门学习教程 前言 今天来学直线测距&#xff0c;主要是用来测量连点之间的线段距离。感觉是用来得到工业产品精度的。 文章解读 一维测距是非常简单的这里…

稳定的音频来了 — 使用人工智能创作音乐(for free)

今天&#xff0c;以稳定扩散&#xff08;Stable Diffusion&#xff09;和StableLM等开源AI工具和模型而闻名的Stability AI公司推出了其首个音乐和声音生成AI产品——StableAudio。音乐产业以其难以打入而闻名。即使您拥有才华和动力&#xff0c;您仍然需要创作和制作音乐所需的…

LaTeX插入裁剪后的pdf图像

画图 VSCode Draw.io Integration插件 有数学公式的打开下面的选项&#xff1a; 导出 File -> Export -> .svg导出成svg格式的文件。然后用浏览器打开svg文件后CtrlP选择另存为PDF&#xff0c;将图片存成pdf格式。 裁剪 只要安装了TeXLive&#xff0c;就只需要在图…

wvp如果确认音频udp端口开放成功

用到工具 在服务器上开启端口监听 选中udp server&#xff0c;点击创建按钮 设置服务器监听端口 在客户端连接服务器端口 选中udp客户端&#xff0c;点击创建 输入服务器地址 远程端口和本地端口&#xff0c;本地端口只要没被占用都可以使用 &#xff0c;点击确认 发送数据 …

福州大学《嵌入式系统综合设计》 实验九:ROI视频编码

一、实验目的 ROI视频编码即感兴趣区域视频编码&#xff0c;即针对感兴趣区域进行重点编码&#xff0c;提高编码质量&#xff0c;而对非感兴趣区域采用低质量编码。通过这种方法可以降低码率。本实验即让同学们能够在算能的FFMPEG接口下实现基于ROI的视频编码。 二、实验内容…

燃料电池汽车市场分析:预计2028年将达到118亿美元

燃料电池汽车( FCV) 是一种用车载燃料电池装置产生的电力作为动力的汽车。车载燃料电池装置所使用的燃料为高纯度氢气或含氢燃料经重整所得到的高含氢重整气。与通常的电动汽车比较, 其动力方面的不同在于FCV 用的电力来自车载燃料电池装置, 电动汽车所用的电力来自由电网充电的…

C++ AVL 树

AVL树的概念 当数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;此时二叉搜索树的搜索效率低下 解决方法&#xff1a;AVL树&#xff08;降低树的高度&#xff0c;从而减少平均搜索长度) 一棵AVL树或者是空树&#xff0c;或者是具有以下性质的二叉搜索树&#xff1…

C++ 通过CryptoPP计算Hash值

Crypto (CryptoPP) 是一个用于密码学和加密的 C 库。它是一个开源项目&#xff0c;提供了大量的密码学算法和功能&#xff0c;包括对称加密、非对称加密、哈希函数、消息认证码 (MAC)、数字签名等。Crypto 的目标是提供高性能和可靠的密码学工具&#xff0c;以满足软件开发中对…

Android 10.0 Launcher3定制之首页时钟小部件字体大小的修改

1.前言 在10.0的产品开发中,在一些Launcher3的定制化开发中,在对于一些小屏幕的产品开发中,在首页添加时钟小部件会显得字体有点小, 所以为了整体布局美观就需要改动小部件的布局日期字体的大小来实现整体的布局美观效果,接下来来具体实现相关的功能 具体效果图: 2.Lau…

悠络客受邀出席2023上海区域零售(餐饮)数字化运营实战沙龙研讨会

11月23日&#xff0c;由中国零售&#xff08;餐饮&#xff09;CIO俱乐部、《智慧零售与餐饮》主办的2023上海区域零售&#xff08;餐饮&#xff09;数字化运营实战沙龙研讨会在上海召开&#xff0c;悠络客合伙人兼销售副总裁张勇作为演讲嘉宾受邀出席了本次大会。 本次研讨会汇…

Android中使用Google Map

在app的使用过程中&#xff0c;我们经常会跟地图进行交互&#xff0c;如果是海外的应用&#xff0c;那选择使用Google Map 是最合适的选择。 在Android中如何使用Google Map&#xff0c;这里做一个简要的说明。 Google API_KEY的申请 Google Map 的使用并不是免费的&#xf…

小航助学题库蓝桥杯题库c++选拔赛(22年1月)(含题库教师学生账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09; 需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09;

C++面向对象复习笔记暨备忘录

C指针 指针作为形参 交换两个实际参数的值 #include <iostream> #include<cassert> using namespace std;int swap(int *x, int* y) {int a;a *x;*x *y;*y a;return 0; } int main() {int a 1;int b 2;swap(&a, &b);cout << a << &quo…

el-select多选框,数据拼接

将多选框数据 按照逗号拼接为字符串 getTagIds(data, type) {if (type "array") {let array data.join(",")return array} else {let string data.split(",");return string}}, 在调用这个方法时需要&#xff0c;另外传一个字符串type,以此来…

前端:实现二级菜单(点击实现二级菜单展开)

效果 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width, i…