数据结构-链表

链表结构

链表结构五花八门,今天我重点给你介绍三种最常见的链表结构,它们分别是:单链表、双向链表和循环链表。我们首先来看最简单、最常用的单链表。

单链表

我们习惯性地把第一个结点叫作头结点,把最后一个结点叫作尾结点。其中,头结点用来记录链表的基地址。有了它,我们就可以遍历得到整条链表。而尾结点特殊的地方是:指针不是指向下一个结点,而是指向一个空地址 NULL,表示这是链表上最后一个结点。

针对链表的插入和删除操作,我们只需要考虑相邻结点的指针改变,所以对应的时间复杂度是 O(1)。链表随机访问的性能没有数组好,需要 O(n) 的时间复杂度。

循环链表

循环链表是一种特殊的单链表。实际上,循环链表也很简单。它跟单链表唯一的区别就在尾结点。我们知道,单链表的尾结点指针指向空地址,表示这就是最后的结点了。而循环链表的尾结点指针是指向链表的头结点。从我画的循环链表图中,你应该可以看出来,它像一个环一样首尾相连,所以叫作“循环”链表。

从我画的图中可以看出来,双向链表需要额外的两个空间来存储后继结点和前驱结点的地址。所以,如果存储同样多的数据,双向链表要比单链表占用更多的内存空间。虽然两个指针比较浪费存储空间,但可以支持双向遍历,这样也带来了双向链表操作的灵活性。那相比单链表,双向链表适合解决哪种问题呢?从结构上来看,双向链表可以支持 O(1) 时间复杂度的情况下找到前驱结点,正是这样的特点,也使双向链表在某些情况下的插入、删除等操作都要比单链表简单、高效。

头结点即为第一个节点 尾节点指向空地址

带哨兵的节点有利于简化代码,推荐使用

双向链表

循环链表是一种特殊的单链表。实际上,循环链表也很简单。它跟单链表唯一的区别就在尾结点。我们知道,单链表的尾结点指针指向空地址,表示这就是最后的结点了。而循环链表的尾结点指针是指向链表的头结点。从我画的循环链表图中,你应该可以看出来,它像一个环一样首尾相连,所以叫作“循环”链表。

双向循环链表

了解了循环链表和双向链表,如果把这两种链表整合在一起就是一个新的版本:双向循环链表。

双向链表的示例【待添加】

必练操作

接口定义

package com.s1.array;public interface IList {void print();// 往尾部添加void add(Integer data);void addFirst(Integer data);void addLast(Integer data);// 指定位置添加元素(有效范围内)void add(int position, Integer data);// 往尾部删除Object remove();// 删除首元素Object removeFirst();// 删除尾元素Object removeLast();// 删除指定下标的元素Object remove(int index);// 删除指定数据的元素Object remove(Object obj);  // 改1 : 找到下标,然后更改boolean updateByPosition(int position, Integer value);// 改2 : 找到原数据,然后更改boolean updateByData(Integer oldData, Integer newData);void clear();   
}

复制

  • 实现单链表【可选 循环链表、双向链表】,支持增删操作
  • 单链表反转链
  • 表中环的检测
  • 两个有序的链表合并
  • 删除链表倒数第 n 个结点
  • 求链表的中间结点

思考题:基于链表的 LRU 算法

LRU 思路一

  1. 如果此数据之前已经被缓存在链表中了,我们遍历得到这个数据对应的结点,并将其从原来的位置删除,然后再插入到链表的头部。
  2. 如果此数据没有在缓存链表中,又可以分为两种情况: 如果此时缓存未满,则将此结点直接插入到链表的头部; 如果此时缓存已满,则链表尾结点删除,将新的数据结点插入链表的头部。

或者 思路二

    /*** 如果不存在 *   队列未满则插入 tail*   队列已满移除head并从插入 tail         * 如果存在 则从中取出并从插入 tail*/ 

复制

package com.s2.link;public class LRULinkedList extends LinkedList {private static final int DEFAULT_LENGTH = 10;private final int length;private int used = 0;public LRULinkedList() {this(DEFAULT_LENGTH);}public LRULinkedList(int length) {this.length = length;}protected boolean isFull () {return this.used == this.length;}@Overridepublic void add(Integer data) {/*** 如果不存在 *   队列未满则插入 tail*   队列已满移除head并从插入 tail         * 如果存在 则从中取出并从插入 tail*/ Object removeNode = this.remove(data);if (removeNode == null && this.isFull()) {this.removeFirst();     }this.addLast(data);}@Overridepublic Object remove(Object obj) {Object removeObject = super.remove(obj);if (removeObject != null) {this.used--;}       return removeObject;}@Overridepublic Object removeFirst() {Object removeObject = super.removeFirst();if (removeObject != null) {this.used--;}       return removeObject;}@Overridepublic void addLast(Integer data) {super.addLast(data);used++;}
}

复制

思考题:判断是否为回文串

找到中间节点。根据奇偶个数。 如果是奇数个则中分开。 如果是偶数个,则认为中点有两个,继续分开。 然后分别拿到两端的 head 指针就行循环,如果遇到节点的数据不一致则认定不是回文串。若循环结束则认为该串是回文串。

代码片段

    // 判断是否为回文 public boolean palindrome() {// 根据快慢指针找到中间节点, 但是不知道总结点个数是奇还是偶数if (this.headNode == null) {return false;}if (this.headNode.next == null) {return true;}// 大于两个节点Node slow = this.headNode;Node fast = this.headNode;while (fast.next != null && fast.next.next != null) {slow = slow.next;fast = fast.next.next;}//  slow  fast//  1     2//  1     2   3System.out.println("slow " + slow);System.out.println("fast " + fast);Node leftNode;Node rightNode;// 总奇数个, 一个重点if (fast.next == null) {rightNode = slow.next;this.inverseLinkList(slow);leftNode = slow.next;} //  总偶数个数,两个中点 else {rightNode = slow.next;this.inverseLinkList(slow);leftNode = slow;}           return this.TFResult(leftNode, rightNode);}

 

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot 中的事务超时时间

Spring Boot 中的事务超时时间 在 Spring Boot 中,事务管理是一个非常重要的话题。当我们在数据库中执行一些复杂的操作时,需要确保这些操作能够在一定的时间内完成,否则可能会导致数据一致性问题。为了解决这个问题,Spring Boot…

springboot 整合mybatis plus,使用druid 切换多数据源实现单数据库事务,附赠项目源码地址

项目源码地址 GitHub - liyanlei58/ssm: springboot druid mybatis plus 事务 最近想搭一套spring cloud开发环境,各种不顺利吧,先是spring cloud的组件某些功能不好用,是版本自身的bug。后来又碰到了事务无法回滚,这个搞了好几个…

windows的环回网卡(loopback adapter) 安装方法

0.说明:windows的环回网卡(loopback adapter)的作用: microsoft loopback adapter就是安装在本机上的一块虚拟网卡,它跟本机上的其它物理网卡、和物理网卡连接的网络是没有关系的,你可以理解成这块网卡上的网线接到了另外一个空白…

Python 字节数组方式写入kafka(含报错return ‘<SimpleProducer batch=%s>‘ % self.async)

一、背景 项目开发了一个类似kafka tools查询工具的kafka 查询,现在需要测试一下如果通过字节数组的形式写入,看看查询有没有问题 二、kafka查询代码 Python代码示例: from kafka import KafkaProducer import json# 创建Kafka生产者 pro…

美好未来“一束光”儿童安全教育项目在四川泸定正式启动

6月26日,由中华少年儿童慈善救助基金会和北京臻爱公益基金会共同发起的美好未来计划“一束光”儿童安全教育公益项目启动仪式,在四川省甘孜藏族自治州泸定县贡嘎山片区寄宿制学校举行。 出席本次启动仪式活动的嘉宾有:中华少年儿童慈善救助基…

【Spring Boot 事务】万字详解Spring Boot 事务,赶快跟随良辰一起去学习Spring Boot 事务吧! ! !

前言: 大家好,我是良辰丫,这篇文章我将带领大家一起去学习Spring Boot 事务文章,我们在学习数据库的时候已经接触过事务了,来跟随我的脚步一起来瞧一下Spring Boot 事务吧.💌💌💌 🧑个人主页:良辰针不戳 📖…

element框架select值更新页面不回显的问题,动态表单props绑定问题

1、页面中使用form表单&#xff0c;引入select组件 当data中默认没有定义form.region的值时&#xff0c;会出现选择select后input没有回显选择数据值&#xff1b;所以使用select时&#xff0c;必须定义默认值 <el-form ref"form" :model"form" label-…

聊一聊人工智能与视频技术的5大发展趋势与应用

随着互联网的快速发展&#xff0c;视频时代已经到来。据统计&#xff0c;目前互联网内容中&#xff0c;视频内容占据高达82%的流量&#xff0c;未来仍将持续增长。今天我们就来聊一聊关于视频技术的发展&#xff0c;以及现在的大热门–人工智能技术与视频技术的结合。 视频技术…

第38节:cesium 风场效果(含源码+视频)

结果示例: 完整源码: <template><div class="viewer"><vc-viewer @ready="ready" :logo="false"><!

CUDA中的缓存

CUDA缓存包括L1缓存和L2缓存。 SM加载数据&#xff0c;根据不同的设备和类型分为三种路径&#xff1a; 一级和二级缓存常量缓存只读缓存 常规的路径是一级和二级缓存&#xff0c;需要使用常量和只读缓存的需要在代码中显式声明。但是提高性能&#xff0c;主要还是要取决于访问…

茶油生产加工MES质量溯源平台源码(spring boot+mybatis+easyui+mysql+h5)

一、生产加工MES&#xff08;Manufacturing Execution System&#xff0c;简称MES&#xff09;是一种面向车间的生产过程管理与实时信息系统。它主要负责监控生产过程&#xff0c;管理生产资源&#xff0c;优化生产流程&#xff0c;提高生产效率和质量。MES系统需要与ERP系统、…

Android TV:自定义Leanback的VideoDetailsFragment

在Android studio新建TV项目的demo上做修改,实现一下需求: 1、去掉顶部背景区域 2、修改中间详情区域高度 3、修改整体背景界面 效果如图: 搜遍全网,没有找到一个解决方案。只能考自己看代码来自定义实现了。 1、去掉顶部背景区域: VideoDetailsFragment中重写setupD…