数据结构(链表)

news2024/12/25 0:42:36

链表及其实现

链式结构

顺序表插入、删除时间代价的分析,可以看出其时间复杂度是线性阶的,而且会引起大量已存储元素的位置移动。

改进方法:链式结构

Ø各个元素的物理存放位置在存储器中是任意的,不一定连续。
Ø每个元素放在一个独立的存储单元中,元素间的逻辑关系依靠存储单元中附加指针来完成。
Ø采用链式存储结构存储的线性表,称为链表

链表的存储映像图

 

 为了清晰看出逻辑关系,以后链表用图(b)来表示。

 结构类型、结构变量、结构指针

#结构体
struct dateT
{   int year;
    int month;
    int day;
};
#类
class dateT
{  public:
      int year;
      int month;
      int day;
};
#结构变量、结构指针
dateT  d, *p;
d.year = 2020;
d.month = 3;
d.day = 11;
p = &d;
cout<<p->year<<endl;
cout<<p->month<<endl;
cout<<p->day<<endl;

dateT  d, *p;
p = new dataT;
p->year = 1010;
p->month = 1;
d->day = 1;
delete p; 
p->year = 2021; //非法
p = &d;  //合法

  *p在此是指针,在后面delete p,系统回收的是无名氏对应的内存,而不是指针,故可以在后面重新将指针指向没被回收的d内存,p=&d表示指针p指向内存d的起始地址。指针只会在程序结束时由系统自动回收。

结点和链表

 单链表的特点

Ø头指针head指向了头结点。
Ø头结点并不是线性表中的一部分,它的指针字段next给出了首结点的地址。
Ø线性表中最后一个结点的指针字段next的值为NULL。
Ø顺着头指针head,可以很方便地逐个访问单链表中的所有结点。

单链表类

Ø它的任何一个结点包含了一个存储元素数据值的字段和一个存储该结点的直接后继结点地址的指针字段。
Ø提供一个单链表只需要给出头结点的地址即头指针。
Ø单链表结点类定义、单链表类定义

单链表结点类(linkList.h) 

class outOfBound{};
template <class elemType>
class linkList; //类的前向说明

template <class elemType>
class node
{   friend class linkList<elemType>;
     private:
        elemType data;
        node *next;
 public:
        node():next(NULL){};
        node(const elemType &e, node *N=NULL)
        {  data = e; next = N; };
};

单链表类

template <class elemType>
class linkList
{   private:
        node<elemType> *head;
    public:
        linkList();  //构造函数,建立一个空表
        bool isEmpty ()const; //表为空返回true,否则返回false。
        bool isFull ()const {return false;}; //表为满返回true,否则返回false。
        int length ()const;  //表的长度
        elemType get(int i)const;//返回第i个元素的值
        //返回值等于e的元素的序号,从第1个开始,无则返回0.
        int find (const elemType &e )const;
        //在第i个位置上插入新的元素(值为e)。
        void insert (int i, const elemType &e );
        //若第i个元素存在,删除并将其值放入e指向的空间。
        void remove (int i, elemType &e);
        void reverse()const; //元素就地逆置
        void clear (); //清空表,使其为空表
        ~linkList();
};

链表基本操作的实现代码(linkList.h)

template <class elemType>    //属性赋初值,模板函数用法
linkList<elemType>::linkList() //构造函数,建立一个空表
{
    head = new node<elemType>();
}

template <class elemType>
bool linkList<elemType>::isEmpty ()const //表为空返回true,否则返回false。
{
    if (head->next==NULL) return true;
    return false;
}

链表基本操作的实现分析

 

 

插入总结:遵循“先武装自己,再融入队伍”

1.在内存中创建新结点。

2.武装新结点:将x写入新结点的data字段,p指针所指结点的下一结点地址写入新结点的 next字段,使p所指结点的下一结点成为新结点的直接后继结点。

3.将新结点地址写入p的next字段,使新结点成为p所指结点的直接后继结点。

具体语句

#法一
tmp = new node<elemType>(); 
tmp->data = e;
tmp->next = p->next;
p->next = tmp;

#法二
tmp = new node<elemType>(e, p->next);
p->next = tmp;

#法三:四合一语句
p->next = new node<elemType>(e, p->next);

时间复杂度分析:

当P已经指向了插入位置的前一个结点时,插入操作和结点个数无关,时间复杂度为O(1)。

链表基本操作实现代码

template <class elemType>
void linkList<elemType>::insert (int i, const elemType &e )
//在第i个位置上插入新的元素(值为e)。
{   if (i<1) return;//参数i越界
    int j=0; node<elemType>  *p=head;
 
    while (p&&j<i-1)                      //注意此处一定要添加p这一条件,以便确保指针合法
    {  j++;  p=p->next; }
 
    if (!p) return; //参数i越界
    p->next = new node<elemType>(e, p->next);  
}

删除操作: 删除P指针所指结点之后的那个结点

删除总结:

1.记住待删除结点地址。
2.将值为x的结点旁路掉。
3.回收原本存储x的结点占用的空间。

具体语句:

node *q=p->next;
p->next = q->next;
delete q;

时间复杂度分析:

当P已经指向了待删除结点的前一个结点时,删除操作和结点个数无关,时间复杂度为O(1)。

查找操作:

  1. 找值为x的结点,顺首结点逐个向后检查、匹配。
  2. 单链表和顺序表中,时间复杂度都是O(n)。
  3. 找第k个结点,顺序表O(1),链表O(n)。

其他基本操作:

isFull:因每次只申请一个结点空间,故总为false。

clear:除了头结点删除并释放整个单链表中结点,回到初始化后的状态。

template <class elemType>
int linkList<elemType>::length ()const //表的长度
{
    int count=0;
    node<elemType> *p;
    p=head->next;
    while(p)
    {   count++;    p=p->next;  }
    return count;
}


template <class elemType>  //注意:五步口诀法
elemType linkList<elemType>::get(int i )const
//返回第i个元素的值,首元素为第1个元素
{
    if (i<1) throw outOfBound();
    int j=1;
    node<elemType> *p = head->next;
    while (p&&j<i) {p=p->next; j++;}
    if (p) return p->data;
    throw outOfBound();
}
 
template <class elemType>
int linkList<elemType>::find (const elemType &e )const
//返回值等于e的元素的序号,从第1个开始,无则返回0.
{   int i=1;
    node<elemType> *p = head->next;
 
    while (p)
    {   if (p->data==e) break;
        i++;   p=p->next;
    }
    if (p) return i;
    return 0;   }

两种常用技巧:兄弟协同法、首席插入法

兄弟协同法(使用两个指针,在此是指p指针和q指针)

template <class elemType>    //P、Q兄弟协同法
void linkList<elemType>::clear () //清空表,使其为空表
{    node<elemType> *p,*q;
    p=head->next;      head->next=NULL;
    while (p)
    {   q=p->next;
        delete p;
        p=q;
    }
}

 最快插入位置——“脖子”(首席插入法)

template <class elemType>
void linkList<elemType>:: insert(const elemType a[], int n)
{ node *tmp, 
   for (int i=0; i<n; i++)
   {     tmp = new node(a[i], head->next);   head->next = tmp;    }
}

a[5]={1,3,5,7,9}

练习

 练习描述:对一个单链表进行就地逆置---摆龙门阵

 

 

 

 

“兄弟协同法”+“首席插入法”实现单链表的就地逆置

template <class elemType>
void linkList<elemType>::reverse()
{   node<elemType> *p,*q;  //兄弟俩协同
    p=head->next;   head->next = NULL;  
    while (p)
    {  q = p->next;
       p->next = head->next; head->next = p; //首席插入
       p=q;
    }
}

常见错误

Ø指针p未被初始化或者为空,读取其指向的字段如p->data,如循环检查p所指的结点中值是否x,可用while (p && p->data!=x) p=p->next

Øp原本指向了一个结点,但其指向的结点空间已经释放,仍要读取其所指结点的字段。如p=head; delete p; p=p->next;

p->next非法访问了不能访问的内存空间

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

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

相关文章

国产新冠口服药重大突破:疗效不劣于Paxlovid,且安全性更高

*仅供医学专业人士阅读参考最近一段时间&#xff0c;新型冠状病毒感染&#xff08;Covid-19&#xff09;人数的激增&#xff0c;让全国多地迎来了重症“冲击波”&#xff0c;医疗卫生系统承受着极大的压力。 在新冠治疗药物方面&#xff0c;我国当前情况如何&#xff1f;最近Pa…

opencv鱼眼镜头矫正

说明 鱼眼镜头是一种视场角很大的镜头&#xff0c;但是得到的图片有很大的畸变&#xff0c;所以需要对鱼眼镜头进行标定&#xff0c;标定所得的参数可以对鱼眼镜头的图像进行矫正。 下图来自opencv的文档。其中c是鱼眼镜头原图&#xff0c;a和b是不同的矫正方法得到的图片。 …

K8S部署Apollo配置中心

K8S部署Apollo配置中心 参考文档: https://github.com/apolloconfig/apollo/tree/v1.8.0 [K8S部署apollo配置中心](https://www.cnblogs.com/Fengyinyong/p/14903725.html)[apollo官网文档](https://www.apolloconfig.com/#/zh/README)1、错误问题记录 在k8s里面部署时也遇到…

UDS-11.2 ReadDataByIdentifier (22) service

11.2.1 服务描述 来自&#xff1a;ISO 14229-1-2020.pdf ReadDataByIdentifier服务允许客户端从由一个或多个dataidentifier标识的服务器请求数据记录值。 客户端请求消息包含一个或多个两个字节的dataIdentifier值&#xff0c;用于标识由服务器维护的数据记录(关于允许的dataI…

【监督-非监督组合:全色锐化】

Supervised-unsupervised combined deep convolutional neural networks for high-fidelity pansharpening &#xff08;监督-非监督组合深度卷积神经网络实现高保真全色锐化&#xff09; 深度学习全色锐化方法因其优异的性能成为近年来的研究热点&#xff0c;基于Wald协议的卷…

GBASE合芯科技打造“国产芯片+数据库”国产替代解决方案

数据库的重要性 数据库是国产化基础软件的重要部分&#xff0c;是信息系统的核心。我国信息技术软硬件底层标准、架构、产品、以及生态体系被外国把控&#xff0c;这些上游核心技术遭遇限制严重影响了我国关键科技和产业的发展。2018年&#xff0c;中兴通讯被列入美国实体清单…

2022/12/29总结

今天AC了一道题目&#xff1a; P1825 [USACO11OPEN]Corn Maze S (1条消息) P1825 [USACO11OPEN]Corn Maze S_lxh0113的博客-CSDN博客 然后下面是学到的知识&#xff1a; 之前学习算法的时候总是牵扯到图&#xff0c;但是关于图的一些知识并没有了解。下面是有关图的基础知识…

区块链技术的官方材料整理

引自&#xff1a;区块链白皮书&#xff08;2018年&#xff09;、区块链白皮书&#xff08;2020年&#xff09;、中国区块链技术和应用发展白皮书、可信区块链赋能数字政府应用指南 区块链的概念 定义&#xff1a;区块链&#xff08;Blockchain&#xff09;是一种由多方共同维…

如何在 SwiftUI macOS 应用程序中显示和隐藏边栏

用户可以通过在边缘周围拖动来调整侧边栏的大小。 如果他们将它拖得足够远,侧边栏将关闭,并且无法将其设置回来。 本文将告诉您如何通过添加其他选项来显示和隐藏边栏来缓解此问题。 侧边栏一旦折叠,就无法恢复。 拖动左边缘会调整窗口大小,而不是将侧边栏带回来。 有两种…

力扣 1764. 通过连接另一个数组的子数组得到一个数组

题目 给你一个长度为 n 的二维整数数组 groups &#xff0c;同时给你一个整数数组 nums 。 你是否可以从 nums 中选出 n 个 不相交 的子数组&#xff0c;使得第 i 个子数组与 groups[i] &#xff08;下标从 0 开始&#xff09;完全相同&#xff0c;且如果 i > 0 &#xff…

【大型电商项目开发】订单功能实现(拦截器、feign丢失请求头、接口幂等性)-55

一&#xff1a;订单概念 1.1 订单中心 电商系统涉及到 3 流&#xff0c;分别时信息流&#xff0c;资金流&#xff0c;物流&#xff0c;而订单系统作为中枢将三者有机的集合起来。订单模块是电商系统的枢纽&#xff0c;在订单这个环节上需求获取多个模块的数据和信息&#xff0…

多线程问题(三)

目录 一、线程安全的单例模式 1、饿汉模式 2、懒汉模式 二、阻塞队列 三、定时器 1、标准库中定时器的使用用法 2、模拟实现定时器 a、首先需要创建出一个专门的类来表示schedule中的任务&#xff08;TimerTask&#xff09; b、使用合适的数据结构组织任务 c、…

Servlet基础教程 (保姆级教学)

Servlet基础教程一、Servlet 是什么二、第一个 Servlet 程序2.1 创建项目2.2 引入依赖2.3 创建目录2.4 编写代码2.5 打包程序2.6 部署程序2.7 验证程序三、更方便的部署方式3.1 安装 Smart Tomcat 插件3.2 配置 Smart Tomcat 插件四、常见的访问出错4.1 出现 4044.2 出现 4054.…

【jrebel and xrebel问题记录】激活时出现LS client not configued

教程目录问题描述所使用的环境和版本解决过程手动下载jrebel结束语问题描述 笔者在重装另一台电脑的时候又遇到了这个安装jrebel and xrebel进行激活的问题 但是我在网上找了很多的办法&#xff08;其实都是相同的办法&#xff0c;只是在尝试别人不同的用于激活的服务器&#…

【Java编程进阶】方法初识

推荐学习专栏&#xff1a;Java 编程进阶之路【从入门到精通】 文章目录1. Java 方法初识2. 方法的创建与使用3. 方法的分类3.1 无参无返回值3.2 无参带返回值3.3 有参无返回值3.4 有参带返回值4. 递归方法5. 总结1. Java 方法初识 方法是组合在一起来执行操作语句的集合&#…

k8s收集日志

k8s收集日志 一.收集控制台日志 采用fluentdeskibana来做 所需要的文件可以在这里找 https://github.com/kubernetes/kubernetes/tree/v1.23.0/cluster/addons/fluentd-elasticsearch1.创建目录并下载所需文件 cd /root/k8s/yaml/efk [rootworker1 efk]# ll total 44 -rw-…

绝缘子红外图像检测项目(TF2)

目录 1. 项目背景 2. 图像数据集介绍 labelimg的安装流程&#xff1a; 1. 打开Anaconda Prompt&#xff08;Anaconda3&#xff09; 2. 创建一个新环境来安装labelimg 3. 激活新创建的环境labelimg 4.输入 5.输入labelimg 即可运行 3. 模型介绍 4. 模型性能测试 1. 项目…

Linux学习笔记——Linux实用操作(二)

04、Linux实用操作 4.6、IP地址、主机名 4.6.1、IP地址、主机名 学习目标&#xff1a; 掌握什么是IP地址掌握什么是主机名掌握什么是域名解析 4.6.1.1、IP地址 1、每一台联网的电脑都会有一个地址&#xff0c;用于和其它计算机进行通讯。 IP地址主要有2个版本&#xff0…

2023上半年软考高级-信息系统项目管理师【名师授课班】

信息系统项目管理师是全国计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试&#xff08;简称软考&#xff09;项目之一&#xff0c;是由国家人力资源和社会保障部、工业和信息化部共同组织的国家级考试&#xff0c;既属于国家职业资格考试&#xff0c;又是职称资…

2022年圣诞节 | matlab实现炫酷的圣诞树

*2022年圣诞节到来啦&#xff0c;很高兴这次我们又能一起度过~ 这里的部分代码已经在网上出现过&#xff0c;做了部分优化。是matlab版本。 一、内容介绍 这段代码是一个生成3D圣诞树的Matlab函数。运行该函数时&#xff0c;它使用圆柱函数创建圣诞树的 3D 表面&#xff0c;对…