数据结构与算法--链表实现以及应用

数据结构与算法–链表实现以及应用

  • 链表是面试时候使用最频繁的一种数据结构。链表的结构简单,他由指针将若干个节点链接成链状结构。链表的创建,插入,删除,查询操作都只有几行代码可以完成,代码量比较少,可以在较短的时间内完成,这样可以在短时间内考察出人员对数据结构的理解。而且链表数据结构很灵活,可以用来各种灵活的试题。
  • 链表是一种动态数据结构,因为在建立链表的时候,无需知道链表的长度,当插入一个节点时候,只需要为新节点分配内存,然后调整链表中对应节点的指针指向就可以完成节点的插入。内存分配不是在创建链表的时候一次性完成,而是每添加一个节点分配一个节点的内存,由于没有和数组一样的闲置的内存,所以链表比之数组的内存利用率更高。
  • 我们用如下方式定义链表节点:
/*** 链表元素节点** @author liaojiamin* @Date:Created in 12:17 2021/3/5*/
public class ListNode implements Comparable<ListNode> {private String key;private Integer value;private ListNode next;private ListNode before;public ListNode() {}public ListNode(String key, Integer value){this.key = key;this.value = value;this.next = null;this.before = null;}public ListNode(Integer value) {this.value = value;this.next = null;this.before = null;}public String getKey() {return key;}public void setKey(String key) {this.key = key;}public Integer getValue() {return value;}public void setValue(Integer value) {this.value = value;}public ListNode getNext() {return next;}public void setNext(ListNode next) {this.next = next;}public ListNode getBefore() {return before;}public void setBefore(ListNode before) {this.before = before;}@Overridepublic int compareTo(ListNode o) {return this.value - o.value;}
}
  • 话不多说,我们如下实现单向链表的CURD
/*** 单向链表实现** @author liaojiamin* @Date:Created in 12:21 2021/3/5*/
public class MyLinkedList {/*** 链表尾部添加节点*/public static ListNode addToTail(ListNode head, String key, Integer value) {ListNode newNode = new ListNode(key, value);if (head == null) {head = newNode;}else {ListNode pointNode = head;while (pointNode.getNext() != null){pointNode = pointNode.getNext();}pointNode.setNext(newNode);}return head;}/*** 链表尾部添加节点*/public static ListNode addToTail(ListNode head, ListNode newNode) {if (head == null) {head = newNode;}else {ListNode pointNode = head;while (pointNode.getNext() != null){pointNode = pointNode.getNext();}pointNode.setNext(newNode);}return head;}/*** 从头打印链表数据* */public static void print(ListNode head){if(head == null){System.out.println("is empty list");}ListNode pointNode = head;while (pointNode != null){System.out.print(pointNode.getValue());System.out.print(", ");pointNode = pointNode.getNext();}}/*** 查找节点* */public static ListNode search(ListNode head, Integer value){if(head == null || value == null){System.out.println("not in");}ListNode pointNode = head;while (pointNode != null){if(pointNode.getValue() == value){System.out.println("is in");return pointNode;}else {pointNode = pointNode.getNext();}}System.out.println("not in");return null;}/*** 通过key查找节点* */public static ListNode search(ListNode head, String key){if(head == null || key == null){System.out.println("not in");}ListNode pointNode = head;while (pointNode != null){if(pointNode.getKey().equals(key)){System.out.println("is in");return pointNode;}else {pointNode = pointNode.getNext();}}System.out.println("not in");return null;}/*** 删除节点* */public static ListNode delete(ListNode head, Integer value){if(head == null || value == null || head.getNext() == null){return head;}ListNode delNode= null;if(head.getValue() == value){head = head.getNext();delNode = head;}else {ListNode pointNode = head;while (pointNode.getNext() != null && pointNode.getNext().getValue() != value){pointNode = pointNode.getNext();}if(pointNode.getNext() != null && pointNode.getNext().getValue() == value){delNode = pointNode.getNext();pointNode.setNext(pointNode.getNext().getNext());}}if(delNode != null){System.out.println("delete success val="+ delNode.getValue());}return head;}public static void main(String[] args) {Random random = new Random(100);ListNode myHead = new ListNode(random.nextInt(100));for (int i = 0; i < 20; i++) {addToTail(myHead, random.nextInt(100));}print(myHead);if(search(myHead, 74)){delete(myHead, 74);}print(myHead);System.out.println();// printOver(myHead);System.out.println();// printOver_2(myHead);}
}
  • 由于链表内存不是一次性分配,所以内存是不连续的,通过指针来关键每个节点的内存地址,因此我们也不能像数组一样通过下标去获取对应的节点,只能从头开始遍历节点找到第 i 个节点,时间复杂度是O(n)。

变种题型

  • 简单的单向链表实现的基础上,我们看一个特别的:从尾到头打印单向链表中每个节点值
分析
  • 单向链表从尾开始打印,简单的做法是将链表中的指针反转,但是这样会改变元数据的结构,但是打印一般是只读的,这样显然不可行
  • 顺序打印可以直接从头结点开始读取就可以,要从尾到头反转,也就是说有如下特性:第一个先遍历,但是他必须最后输出,此时我们可以借助其他的数据结构,将第一次遍历看出输入,也就是第一个输入的必须最后一个输出,这是典型的先进后出的顺序,栈很显然符合这种标准,我们有如下实现:
 /*** 栈方法,* 从尾到头打印单向链表值* */public static void printOver(ListNode head){MyStack myStack = new MyStack();if(head == null){return;}ListNode pointNode = head;while (pointNode != null){myStack.push(pointNode.getValue().toString());pointNode = pointNode.getNext();}while (!myStack.isEmpty()){System.out.print(myStack.pop());System.out.print(", ");}}
  • 注意:此处用的myStack用的上一节中自己实现的栈,详情点击
  • 以上实现用栈可以实现,那么一定可以用递归来完成,因为递归本质上就是栈的一种结构,那么我们用递归每次打印节点的时候都判断是否有子节点,有则下打印子节点,如下实现。
/*** 递归方式* 从尾到头打印单向链表* */public static void printOver_2(ListNode head){if(head == null){return;}ListNode pointNode = head;if(pointNode.getNext() != null){printOver_2(pointNode.getNext());}System.out.print(pointNode.getValue());System.out.print(", ");}
  • 问题:以上递归方式的代名词看起来更简单一点,但是有一个问题,当链表长度非常长的时候,可能会导致函数栈溢出。而之前用栈的方法虽然需要两次循环但是代码的鲁棒性还是要更好一点,因此我认为最优解是使用栈的方式。

上一篇:数据结构与算法–利用栈实现队列
下一篇:数据结构与算法–查找与排序另类用法

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

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

相关文章

还不会docker+k8s?2020年,就要面对现实了...

docker的前世今生2010年&#xff0c;几个年轻人&#xff0c;在美国旧金山成立了一家名叫“dotCloud”的公司。这家公司主要提供基于PaaS的云计算技术服务。具体来说&#xff0c;是和LXC有关的容器技术。后来&#xff0c;dotCloud公司将自己的容器技术进行了简化和标准化&#x…

数据结构与算法--重建二叉树

二叉树 树在实际编程中经常遇到地一种数据结构。上一篇中我们解释了二叉树及其原理&#xff0c;从中可以知道&#xff0c;树地操作会涉及到很多指针地操作&#xff0c;我们一般遇到地树相关地问题差不多都是二叉树。二叉树最重要地莫过于遍历&#xff0c;即按照某一顺序访问树…

3分钟掌握Quartz.net分布式定时任务的姿势

长话短说&#xff0c;今天聊一聊分布式定时任务&#xff0c;我的流水账笔记&#xff1a;ASP.NET CoreQuartz.Net实现web定时任务AspNetCore结合Redis实践消息队列细心朋友稍一分析&#xff0c;就知道还有问题&#xff1a;水平扩展后的WebApp的Quartz.net定时任务会多次触发&…

C++ 实现布隆过滤器(BloomFilter)

代码如下: #include <iostream> #include <vector> using namespace std;class BitMap { public:BitMap(size_t range) :_bit(range / 32 1) {}void set(const size_t num){int idx num / 32;//idx 数组下标int bitIdx num % 32;_bit[idx] | 1 << bitIdx…

数据结构与算法--利用栈实现队列

利用栈实现队列 上一节中说明了栈的特点 后进先出&#xff0c;我们用数组的方式实现了栈的基本操作api&#xff0c;因此我们对栈的操作是不考虑排序的&#xff0c;每个api的操作基本都是O(1)的世界&#xff0c;因为不考虑顺序&#xff0c;所以找最大&#xff0c;最小值&#x…

ASP.NET Core 配置源:实时生效

在之前的文章 ASP.NET Core 自定义配置源 和 ASP.NET Core etcd 配置源 中主要是介绍如何实现自定义的配置源&#xff0c;但不论内置的和自定义的配置源&#xff0c;都会面临如何使配置修改后实时生效的问题&#xff08;修改配置后在不重启服务的情况下能马上生效&#xff09;。…

分布式事务理论模型

分布式事务 事务的概念&#xff0c;我们第一想到的应该是数据库的事务。所谓数据库事务就是只作为单个逻辑工作单元执行多个数据库操作的时候&#xff0c;数据库需要保证要么都成功&#xff0c;要么都失败&#xff0c;它必须满足ACID特性&#xff0c;即&#xff1a; 原子性&…

[MySQL基础]数据库的相关概念

DB: 数据库(database):存储数据的“仓库”&#xff0c;它保存了一系列有组织的数据。 DBMS: 数据库管理系统(Database Management System):数据库是通过DBMS创建和操作的容器。 SQL: 结构化查询语言(Structure Query Language):专门用来与数据库通信的语言。 SQL的优点: 1.几…

Linq下有一个非常实用的SelectMany方法,很多人却不会用

在平时开发中经常会看到有些朋友或者同事在写代码时会充斥着各种for&#xff0c;foreach&#xff0c;这种程式代码太多的话阅读性特别差&#xff0c;而且还显得特别累赘&#xff0c;其实在FCL中有很多帮助我们提高阅读感的方法&#xff0c;而现实中很多人不会用或者说不知道&am…

.NET Core前后端分离快速开发框架(Core.3.1+AntdVue)

引言时间真快&#xff0c;转眼今年又要过去了。回想今年&#xff0c;依次开源发布了Colder.Fx.Net.AdminLTE(254Star)、Colder.Fx.Core.AdminLTE(335Star)、DotNettySocket(82Star)、IdHelper(47Star)&#xff0c;这些框架及组件都是本着以实际出发&#xff0c;实事求是的态度&…

数据结构与算法--查找与排序另类用法-旋转数组中的最小数字

查找与排序 查找 查找与排序都在程序设计中常被用到的算法。查找相对而言简单&#xff0c;一般都是顺序查找&#xff0c;二分查找&#xff0c;哈希表查找&#xff0c;和二叉排序树查找。其中二分查找是我必须熟悉的一种。哈希表和二叉排序树主要点在于他的数据结构而不是算法…

[MySQL基础]MySQL常见命令介绍

show databases; use 库名; show tables; show tables from 库名 select database(); create table 名字( id int, name varchar(20)); desc 表名; select * from 表名; insert into 表名 (a,b,…,f) values(1,2,3,…,7); update 库名 set name‘lilei’ where id1; delete f…

如何选择好公司

点击蓝字关注&#xff0c;回复“职场进阶”获取职场进阶精品资料一份前几天写了一篇文章&#xff1a;怎么判断自己在不在一家好公司。附带了一个投票调查&#xff0c;结果如下图&#xff1a;调研结果有点点扎心&#xff0c;有点点出乎我的意料。61%的小伙伴&#xff0c;都认为自…

数据结构与算法--再谈递归与循环(斐波那契数列)

再谈递归与循环 在某些算法中&#xff0c;可能需要重复计算相同的问题&#xff0c;通常我们可以选择用递归或者循环两种方法。递归是一个函数内部的调用这个函数自身。循环则是通过设置计算的初始值以及终止条件&#xff0c;在一个范围内重复运算。比如&#xff0c;我们求累加…

[MySQL基础]MySQL语法规范介绍

MySQL的语法规范: 1.不区分大小写&#xff0c;但建议关键字大写&#xff0c;表名&#xff0c;列名小写。 2.每条命令最好用分号结尾。 3.每条命令根据需要&#xff0c;可以进行缩进&#xff0c;或换行。 4.注释 单行注释:#注释文字 单行注释:-- 注释文字 多行注释:/* 注释文…

同步异步多线程这三者关系,你能给面试官一个满意的回答吗?

前几天一位朋友去面试&#xff0c;面试官问了他同步&#xff0c;异步&#xff0c;多线程之间是什么关系&#xff0c;异步比同步高效在哪&#xff1f;多线程比单线程高效在哪&#xff1f;由于回答的不好&#xff0c;让我帮他捋一下&#xff0c;其实回答这个问题不难&#xff0c;…

分布式事务框架seata

seata 前两篇文中总结了一下分布式事务已经现阶段常用的解决方案&#xff0c;现在来讨论一下现有的分布式事务框架seata&#xff0c;点击此处是seata的官网seata致力于微服务框架下提供高性能和简单易用的分布式事务服务。它提供了AT&#xff0c;TCC&#xff0c;Saga &#xf…

[一起读源码]走进C#并发队列ConcurrentQueue的内部世界 — .NET Core篇

在上一篇《走进C#并发队列ConcurrentQueue的内部世界》中解析了Framework下的ConcurrentQueue实现原理&#xff0c;经过抛砖引玉&#xff0c;得到了一众大佬的指点&#xff0c;找到了.NET Core版本下的ConcurrentQueue源码&#xff0c;位于以下地址&#xff1a;https://github.…

Java语法基础50题训练(上)

题目1: 有两只老虎&#xff0c;一只体重为180kg&#xff0c;一只体重为200kg&#xff0c;请用程序实现判断两只老虎的体重是否相同。 代码如下: public class OperatorTest {public static void main (String[] args) {int w1 180;int w2 200;boolean ans w1 w2?true:f…