c++单链表的简单实现(内含实现代码)

2023-11-08

考研报名等待之时闲来无事,写了一个简单的单链表。

简单实现了以下功能:

  1. 头插法建立单链表
  2. 按序遍历链表
  3. 单链表原地排序(不使用额外的空间)
  4. 单链表按序删除
  5. 单链表原地倒置

附上代码如下:

节点结构体定义

typedef int ElemType;

typedef struct Lnode{
    ElemType data;
    struct Lnode * next;
}Lnode, *Linklist;

头插法建立单链表

// 初始化单链表
Linklist initLinkList()
{
    int n;
    cout << "how many nodes do you want to creat?" << endl;
    cout << "input : ";
    cin >> n;

    // 创建头节点
    Lnode * L;
    L = (Linklist)malloc(sizeof(Lnode));
    L -> next = NULL;
    Lnode * rear = L;

    while(n--)
    {
        Lnode * p;
        p = (Linklist)malloc(sizeof(Lnode));
        ElemType data;
        cout << "input data: ";
        cin >> data;
        p -> data = data;

        // 使用尾插法
        p -> next = rear -> next;
        rear -> next = p;
        rear = p;
    }

    return L;
}

按序遍历链表

// 遍历单链表
void Traversal(Linklist L)
{
    Lnode * p = L-> next;
    while(p)
    {
        cout << p -> data << " ";
        p = p -> next;
    }
    cout << endl;

    cout << endl;
}

单链表原地排序

void sort(Linklist &L)
{
    // 使用头插法,顺序插入
    Lnode *p = L -> next, *s, *pre;
    L -> next = NULL;

    // 按照顺序依次插入
    while(p)
    {
        // 保存p节点的下一个节点
        s = p -> next;

        // 将p节点插入链表中,即找到插入p节点的前一个节点pre,将p插入到pre之后
        pre = L;
        while(pre -> next && pre -> next -> data < p->data)
            pre = pre -> next;

        p -> next = pre -> next;
        pre -> next = p;

        // 将p还原
        p = s;
    }   
}

空间复杂度为O(1),时间复杂度为O(n^2)
该算法的实现也可以采用以空间换时间的方法,将单链表存储到数组中,使用时间复杂度为O(nlogn)的算法,但是相应的空间复杂度会上升为O(n)

按序删除单链表

// 删除单链表
void ruin(Linklist L)
{
    Lnode * p = L-> next, *s;

    // 遍历删除每一个节点
    while(p)
    {
        s = p;
        p = p->next;
        cout << "Node which data is " << s->data << " has been deleted!" << endl;
        free(s);
    }

    cout << "head node delete!" << endl;
    free(L); 
}

原地倒置

// 单链表倒置
void reverse(Linklist &L)
{
    // 基本思想为,从第一个结点开始,使用头插法依次插入到头节点之后
    Lnode *p = L -> next, *s;
    L -> next = NULL;

    while(p)
    {
        s = p -> next;

        p -> next = L -> next;
        L -> next = p;

        p = s;
    }
}

空间复杂度为O(1), 时间复杂度为O(n)

代码整体如下(包括一部分测试)

# include<iostream>
using namespace std;

// 数据类型定义
typedef int ElemType;

// 节点结构定义
typedef struct Lnode{
    ElemType data;
    struct Lnode * next;
}Lnode, *Linklist;


// 初始化单链表
Linklist initLinkList()
{
    int n;
    cout << "how many nodes do you want to creat?" << endl;
    cout << "input : ";
    cin >> n;

    // 创建头节点
    Lnode * L;
    L = (Linklist)malloc(sizeof(Lnode));
    L -> next = NULL;
    Lnode * rear = L;

    // 尾插法依次插入节点
    while(n--)
    {
        Lnode * p;
        p = (Linklist)malloc(sizeof(Lnode));
        ElemType data;
        cout << "input data: ";
        cin >> data;
        p -> data = data;

        // 使用尾插法
        p -> next = rear -> next;
        rear -> next = p;
        rear = p;
    }

    return L;
}


// 遍历单链表
void Traversal(Linklist L)
{
    Lnode * p = L-> next;
    while(p)
    {
        cout << p -> data << " ";
        p = p -> next;
    }
    cout << endl;

    cout << endl;
}


// 删除单链表
void ruin(Linklist L)
{
    Lnode * p = L-> next, *s;

    // 遍历删除每一个节点
    while(p)
    {
        s = p;
        p = p->next;
        // cout << "Node which data is " << s->data << " has been deleted!" << endl;
        free(s);
    }

    // cout << "head node delete!" << endl;
    free(L); 
    cout << "delete success!" << endl;
}


// 单链表排序
void sort(Linklist &L)
{
    // 使用头插法,顺序插入
    Lnode *p = L -> next, *s, *pre;
    L -> next = NULL;

    // 按照顺序依次插入
    while(p)
    {
        // 保存p节点的下一个节点
        s = p -> next;

        // 将p节点插入链表中,即找到插入p节点的前一个节点pre,将p插入到pre之后
        pre = L;
        while(pre -> next && pre -> next -> data < p->data)
            pre = pre -> next;

        p -> next = pre -> next;
        pre -> next = p;

        // 将p还原
        p = s;
    }   
}


// 单链表倒置
void reverse(Linklist &L)
{
    // 基本思想为,从第一个结点开始,使用头插法依次插入到头节点之后
    Lnode *p = L -> next, *s;
    L -> next = NULL;

    while(p)
    {
        s = p -> next;

        p -> next = L -> next;
        L -> next = p;

        p = s;
    }
}


int main()
{
    // 初始化
    Linklist L = initLinkList();
    
    // 遍历
    cout << "start traversal! " << endl;
    Traversal(L);

    // 排序
    cout << "after sort, link list is :" << endl;
    sort(L);
    Traversal(L);

    // 倒置
    cout << "after reverse, link list is: " << endl;
    reverse(L);
    Traversal(L);    

    // 删除
    cout << "delete linklist" << endl;
    ruin(L);

    return 0;
}



就这样!感谢阅读!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c++单链表的简单实现(内含实现代码) 的相关文章

  • 光纤收发器A,B端含义解释

    最近有朋友问到 光纤收发器型号或者收发器模块上A B字母的含义是什么 今天飞畅科技的小编就来为大家介绍一下 收发器中A B端字母的真正含义 一起来看看吧 首先 光纤收发器按光纤芯数分类有2种 一种是单模双纤光纤收发器 一种是单模单纤光纤收发
  • (二叉树)二叉树的序列化与反序列化

    题目描述 序列化是将一个数据结构或者对象转换为连续的比特位的操作 进而可以将转换后的数据存储在一个文件或者内存中 同时也可以通过网络传输到另一个计算机环境 采取相反方式重构得到原数据 请设计一个算法来实现二叉树的序列化与反序列化 这里不限定
  • Highway network

    Highway Network主要解决的问题是 网络深度加深 梯度信息回流受阻造成网络训练困难的问题 假设定义一个非线性变换为 定义门函数 携带函数 对于门函数取极端的情况0 1会有 而对应的门函数使用sigmoid函数 则极端的情况不会出
  • Java接口详解

    一 static静态关键字 定义变量不加static关键字 每个对象单独保存一个变量 定义变量加static关键字 静态变量 类变量 共享变量 public static 数据类型 变量名 所有对象会共享该变量 如果一个变量 静态变量 类变
  • C++友元函数

    友元 让函数或者类作为另外一个类的朋友 则可以访问当前类的private或者protected 友元friend机制允许一个类授权其他的函数访问它的非公有成员 友元声明以关键字friend开头 它只能出现在类的声明中 它们不受其在类体中的p
  • node.js系统学习2

    1 最基础的东西 也很实用 用于工作 本地搭建一个简单的服务 实际工作中 有很多时候可能你自己需要一个简单的静态服务 但是你发现你的同事全都有 你没有 人家看一个那个产品原型直接用静态服务看 人家看一个文件直接用静态服务看 而你就很lowb
  • docker 简单运用,使用阿里镜像

    第一步 确定docker已经安装 第二步 去阿里上搜索镜像 找到你想要的镜像 然后点击详细中有命行 如下 注意后面加版本号 如 V1 0 docker pull registry cn hangzhou aliyuncs com kenny
  • 【JavaEE】线程安全

    文章目录 1 前言 2 线程安全的概念 3 造成线程不安全的原因 4 如何解决出现的线程不安全问题 4 1 如何使用 synchronized 加锁 4 2 解决上面自增问题导致的线程安全问题 5 synchronized 的特性 5 1
  • STM32 输入捕获的脉冲宽度及频率计算

    输入捕获模式可以用来测量脉冲宽度或者测量频率 STM32 的定时器 除了 TIM6 和 TIM7 其他定时器都有输入捕获功能 以下是对脉冲宽度及频率的计算 1 脉冲宽度 如下图所示 采集该高电平脉冲的宽度 只需要进入输入捕获上升沿检测 记录
  • 查看文件中关键字前后几行的内容

    有时候文件太大 我们无法全部看完 去查找我们想要的内容 这时我们需要linux命令来查看某个关键字前后几行的内容 grep 使用linux的help命令 如下图 我们可以看到grep的用法 这里我们关注关键字前后的显示问题 以文件test
  • elk多项目收集

    1 filebeat配置 gt etc filebeat filebeat yml filebeat prospectors type log enabled true paths root project logs all all log
  • BACnet MSTP协议485功能测试

    文章目录 BACnet MSTP协议485功能测试 一 命令行运行方法 二 测试工具 1 使用sscom串口助手 2 使用yabe查看结果 三 代码部分 1 包含头文件 2 变量和宏定义 2 RS485配置函数 3 RS485初始化函数 使
  • 【容器适配器的认识与模拟】

    目录 前言 一 引入 二 容器适配器 一 stack deque stack模拟实现 二 queue queue模拟实现 为什么栈和队列要使用deque 三 priority queue priority queue模拟实现 总结 前言 打
  • AngularJS 学习笔记(四)--- 表单验证和常用API

    一 表单验证 1 概念 AngularJS 表单和控件可以对输入的数据进行验证 并对用户输入的非法数据进行警告 一般来说就算前端进行了验证 后端为了安全还是要再次进行验证 HTML5的表单本身带有一定的验证能力 可以与 AngularJS
  • 最新JetBrains PyCharm 使用教程--常用快捷键和设置PyCharm为Eclipse快捷键(四)

    PyCharm常用快捷键使用 Ctrl D 复制当前行 Ctrl Y 删除当前行 Ctrl Z 撤销 Shift Enter 快速换行 Ctrl 快速注释 Ctrl F 查找 Ctrl H 替换 Tab 缩进 Shift Tab 取消缩进
  • nginx 转发webSocket连接请求

    一 导读 nginx 是一个反向代理的轻量服务器 能对http请求进行转发 但是最新学习websocket发现 普通的nginx转发http请求时候无法转发websocket请求 今天就来介绍一下nginx如何转发websocket请求 与
  • 初识上下文切换

    上下文切换 什么是上下文切换 在单个处理器时期 操作系统就能够多线程并发执行任务 处理器给每个线程分配CPU时间片 线程在分配的时间片内执行任务 CPU时间片是CPU分配给每个线程执行的时间片段 一般几十毫秒 在这么短的时间里线程互相切换
  • 如何在excel中单独冻结多行或多列

    方法 1 首先打开相应的excel表格 确定要冻结的冻结的多行或多列 下面以冻结多行为例 先在界面上找到 视图 冻结窗格 最后找到 冻结首行 2 点击 冻结首行 后 在表格第一行下面会出现一条细实线 此时再点击 拆分 选项 3 拆分后 细实
  • 通过浏览器控制台使用js脚本进行浏览器操作(定时点击等)

    进行此操作前我们首先需要了解js编程语言 了解之后我们就可以去操作了 这里我们拿csdn评论举例子 点开评论界面右键审查元素 此时我们需要找到输入框dom和评论按钮dom 点击元素之后点击箭头然后去界面上选中文本框核按钮 然后我们就可以知道
  • 解决VSCODE 因为在此系统上禁止运行脚本 报错

    文章转载自 https blog csdn net larpland article details 101349586 学习react的时候 在VSCODE中使用yarn 结果报错 找了下原因 是因为PowerShell执行策略的问题 解

随机推荐