一起学算法(链表篇)

1.链表的概念

       对于顺序存储的结构最大的缺点就是插入和排序的时候需要移动大量的元素,所以链表的出生由此而来

先上代码

// 链表
public class LinkedList<T extends Comparable> {// 结点类class Node {T ele; // 当前结点上的元素内容Node next; // 指向下个结点的索引public Node(T ele) {this.ele = ele;}@Overridepublic String toString() {return ele.toString();}}// 头结点private Node head;// 链表中实际存放结点的个数private int size;// 判断链表是否为空public boolean isEmpty() {return head == null;}// 获取链表中结点的个数public int getSize() {return this.size;}public void addHead(T ele) {this.add(0, ele);}public void addTail(T ele) {this.add(this.size, ele);}// 在指定位置添加结点, 关键点: 找到待插入位置的前一个结点public void add(int index, T ele) {if (index < 0 || index > this.size) {throw new IllegalArgumentException("index is invalid!");}Node node = new Node(ele);// 给链表增加一个虚拟头结点, 解决在链表的头部添加时的特殊处理Node dummyHead = new Node(null);dummyHead.next = head;Node prev = dummyHead;for (int i = 0; i < index; i++) {prev = prev.next;}node.next = prev.next;prev.next = node;// 更新头结点head = dummyHead.next;this.size++;}//根据索引找对应的元素public T get(int index){if(index<0||index>=this.size){return null;}Node cur=head;for (int i = 0; i < index; i++) {cur=cur.next;}return cur.ele;}
//获取头节点的元素public T getFirst(){return get(0);}//获取尾结点的元素public T getLast(){return get(this.size-1);}//判断是否包含该元素public boolean contain(T ele){Node cur=head;for (int i = 0; i < this.size; i++) {if(cur.ele.compareTo(ele)==0){return true;}cur=cur.next;}return false;}//将链表中的某个元素进行替换public void set(T ele,int index) {if(index<0||index>=this.size){}Node cur=head;for (int i = 0; i < index; i++) {cur=cur.next;}cur.ele=ele;}//将链表中的元素进行删除public void delete(int index) {if (index < 0 || index >= this.size) {}//无虚拟头结点
//        if (index == 0) {
//            Node delnode = head;
//            head = delnode.next;
//            delnode.next = null;
//            this.size--;
//        } else {
//            Node pre = head;
//            Node cur = pre.next;
//            for (int i = 1; i < index; i++) {
//                pre = pre.next;
//                cur=cur.next;
//            }
//            Node delnode =cur;
//            pre.next = delnode.next;
//            delnode.next = null;
//            this.size--;
//            cur = cur.next;//有虚拟头节点Node dummyNode=new Node(null);dummyNode.next=head;Node pre=dummyNode;Node cur=pre.next;for (int i = 0; i < index; i++) {pre=pre.next;cur=cur.next;}Node delnode =cur;pre.next = delnode.next;delnode.next = null;this.size--;cur = cur.next;}@Overridepublic String toString() {//IO流StringBuilder sb = new StringBuilder();// 头结点不能动Node cur = head;while (cur != null) {sb.append(cur + "-->");cur = cur.next;}return sb.toString();}
}

1.链表的定义

      链表是由一个个结点组成的,每个结点之间通过链接关系串联起来的,每个结点都有一个前驱、一个后继,最后一个结点的后继结点为空节点

       由链接关系A->B组织起来的两个结点,B称为A的后继结点,A被称为B的前驱结点,链表分为单向链表、双向链表、循环链表等

2.链表结点的定义

       由于该类继承了Comparable,所以该类中的元素具有了比较性,ele代表的是数据域,可以是任意的类型,由编码的人自行指定,next代表指针域,指向后继结点的地址

 

3.虚拟头结点

       为了方便对链表的头结点执行操作,往往会建立一个虚拟头结点,这个结点上也不存储数据,也就是ele字段永远为空,或者是为一个特殊的标识

ListNode dummyNode=new ListNode(head,-1);//后继结点为头结点,默认值为-1

2.链表的遍历

1.遍历的含义

遍历就是从链表头结点开始,对所有的结点一次访问的过程

2.动画演示

       虚拟头节点head用-1进行标识,tmp代表当前遍历到的结点,其中tmp后的数字代表链表结点的索引

 3.链表结点的索引

1.索引的含义

链表结点的索引就是给定一个链表头和一个下标index,通过下标获取到链表第index个元素

2.动画演示

3.代码演示

      //根据索引找对应的元素public T get(int index){if(index<0||index>=this.size){return null;}Node cur=head;for (int i = 0; i < index; i++) {cur=cur.next;}return cur.ele;}

4.链表结点的插入

1.插入的含义

       给定一个链表头和一个位置index(index>=0)和一个值ele生成一个值为ele的结点,并且将它插入到链表第index之后的位置

2.动画演示

 3.演示代码

    // 在指定位置添加结点, 关键点: 找到待插入位置的前一个结点public void add(int index, T ele) {if (index < 0 || index > this.size) {throw new IllegalArgumentException("index is invalid!");}Node node = new Node(ele);// 给链表增加一个虚拟头结点, 解决在链表的头部添加时的特殊处理Node dummyHead = new Node(null);dummyHead.next = head;Node prev = dummyHead;for (int i = 0; i < index; i++) {prev = prev.next;}node.next = prev.next;prev.next = node;// 更新头结点head = dummyHead.next;this.size++;}

5.链表结点的删除

1.删除的含义

        给定一个链表头和一个位置index(index>=1)将位置index的结点删除,并且返回被删除的结点,由于第一个结点是虚拟头结点,所以我们要从索引为1的位置开始

2.动画演示

 3.代码演示

 //将链表中的元素进行删除public void delete(int index) {if (index < 0 || index >= this.size) {}//无虚拟头结点
//        if (index == 0) {
//            Node delnode = head;
//            head = delnode.next;
//            delnode.next = null;
//            this.size--;
//        } else {
//            Node pre = head;
//            Node cur = pre.next;
//            for (int i = 1; i < index; i++) {
//                pre = pre.next;
//                cur=cur.next;
//            }
//            Node delnode =cur;
//            pre.next = delnode.next;
//            delnode.next = null;
//            this.size--;
//            cur = cur.next;//有虚拟头节点Node dummyNode=new Node(null);dummyNode.next=head;Node pre=dummyNode;Node cur=pre.next;for (int i = 0; i < index; i++) {pre=pre.next;cur=cur.next;}Node delnode =cur;pre.next = delnode.next;delnode.next = null;this.size--;cur = cur.next;}

6.链表结点的查找

1.查找的含义

查找的含义就是给定一个值通过遍历链表找到链表值和给定相等的那个结点

2.动画演示

 3.代码演示

      //根据索引找对应的元素public T get(int index){if(index<0||index>=this.size){return null;}Node cur=head;for (int i = 0; i < index; i++) {cur=cur.next;}return cur.ele;}

7.链表结点的修改

1.修改的含义

       给定一个链表头一个位置index(index>=1)和一个值ele,将位置index的结点值修改为ele

2.代码演示

    //将链表中的某个元素进行替换public void set(T ele,int index) {if(index<0||index>=this.size){}Node cur=head;for (int i = 0; i < index; i++) {cur=cur.next;}cur.ele=ele;}

leetcode题单:

返回倒数第k个节点

     // 双指针public int kthToLast(ListNode head, int k) {ListNode fast = head;ListNode slow = head;// 让快指针先走k步for (int i = 0 ; i < k ; i++) {fast = fast.next;}// 再让快指针和慢指针同时移动// 当快指针走到链表结尾时// 慢指针所指向的节点就是目标节点while (fast != null) {fast = fast.next;slow = slow.next;}return slow.val;}

删除链表的倒数第N个节点

  //利用双指针public ListNode removeNthFromEnd(ListNode head, int n) {if(head==null||n<0){return head;}ListNode dummyNode=new ListNode(0,head);ListNode slow=dummyNode;ListNode fast=dummyNode;for (int i = 0; i <n+1; i++) {fast=fast.next;}while(fast!=null){slow=slow.next;fast=fast.next;}slow.next=slow.next.next;return dummyNode.next;}

反转链表

   public ListNode reverseList(ListNode head) {if(head==null||head.next==null){return head;}ListNode resNode=reverseList(head.next);head.next.next=head;head.next=null;return resNode;}public ListNode reverseList(ListNode head) {//如果头结点为空或者是头结点的后继节点为空的话,直接返回头结点if(head==null ||head.next==null){return head;}//定义指针ListNode cur=head;ListNode temp=cur.next;ListNode pre=null;while(cur!=null){temp=cur.next;cur.next=pre;pre=cur;cur=temp;}return pre;}

删除链表中的节点

 public void deleteNode(ListNode node) {node.val=node.next.val;node.next=node.next.next;}

两两交换链表中的节点

 //方法一public ListNode swapPairs(ListNode head) {if(head==null||head.next==null){return head;}ListNode left=head;ListNode right=left.next;ListNode newNode=swapPairs(right.next);left.next=newNode;right.next=left;return right;}//方法二public ListNode swapPairs(ListNode head) {if(head==null||head.next==null){return head;}ListNode r=head;for (int i = 0; i <2; i++) {if(r==null){return head;}r=r.next;}ListNode node=reverse(head,r);head.next=swapPairs(r);return node;}public ListNode reverse(ListNode head,ListNode right){ListNode pre=null,curNode=head,next=null;while(curNode!=right){next=curNode.next;curNode.next=pre;pre=curNode;curNode=next;}return pre;
}//方法三public ListNode swapPairs(ListNode head) {//对入参进行判断if(head==null||head.next==null){return head;}ListNode dummyHead=new ListNode(Integer.MIN_VALUE);dummyHead.next=head;ListNode pre=dummyHead;ListNode cur=pre.next;ListNode next=cur.next;while(cur!=null&&next!=null){cur.next=next.next;next.next=cur;pre.next=next;pre=cur;cur=pre.next;next=cur==null?null:cur.next;}return dummyHead.next ;}//方法四public ListNode swapPairs(ListNode head) {if(head==null||head.next==null){return head;}//将头结点的后继点设置为resListNode res = head.next;//将res.next和res.next.next进行交换head.next = swapPairs(res.next);//原先的res与头结点相连接res.next = head;//返回对应的resreturn res;     }

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

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

相关文章

台式机/工控机通过网线共享笔记本电脑无线网络linux系统下 usb网卡的驱动安装

一、台式机/工控机通过网线共享笔记本电脑无线网络 1、 将台式机通过网线和笔记本连接。 2、 将笔记本的“本地连接”和“无线网络连接”的ipv4均设置为自动获取。 4.修改台式机的IP地址为如下&#xff08;对应笔记本信息&#xff09; IP地址为192.168.XXX.12 子网掩码为255.2…

flask

flask 介绍 # python 界的web框架 -Django&#xff1a;大而全&#xff0c;快速开发&#xff0c;公司内部项目 -Flask&#xff1a;小而精&#xff0c;不具备web开发好多功能&#xff0c;丰富的第三方插件 -FastApi&#xff1a;异步框架&#xff0c;主要为了做前后端…

接口/Web自动化测试如何做?框架如何搭建封装?

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 自动化测试怎么做…

Windows7+内网, 安装高版本nodejs,使用vite+vue3+typescript开发项目

前言&#xff1a;vite只支持高版本的nodejs&#xff0c;而高版本的nodejs只支持windows8及以上&#xff0c;且vite还对浏览器版本有兼容问题。以下均为vite官网截图 1、安装好低版本的nodejs win7系统建议安装13.及以下&#xff0c;我的是12.12.0这个版本。nodejs低版本官网下载…

JavaScript(四)DOM及CSS操作

1、DOM简介 DocumentType: Html的声明标签 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Docume…

网络:SecureCRT介绍

1. 使用Tab键补全时出现^I&#xff0c;如下操作

【万字长文】SpringBoot整合MyBatis搭建MySQL多数据源完整教程(提供Gitee源码)

前言&#xff1a;在我往期的博客介绍了2种关于如何使用SpringBoot搭建多数据源操作&#xff0c;本期博客我参考的是目前主流的框架&#xff0c;把最后一种整合多数据源的方式以博客的形式讲解完&#xff0c;整合的过程比较传统和复杂&#xff0c;不过我依旧会把每个实体类的思路…

利用鸿鹄可观测性监控Istio Ingress网关

一、需求描述 在上一篇《利用Vector和鸿鹄搭建微服务应用的可观测性平台》中&#xff0c;阐述了微服务的基本概念、优点及如何利用鸿鹄来处理分布式应用的日志。本文将进一步讨论微服务架构面临的问题、服务网格及鸿鹄处理Istio Gateway的独特优势。 1.1 微服务架构面临的挑战 …

基于SpringBoot+Vue的地方废物回收机构管理系统设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

企业生产管理的核心工作是什么?

作为管理者&#xff0c;一谈到生产管理&#xff0c;你可能会想到很多生产过程中的问题&#xff1a; 产量无法实时统计&#xff1b; 计划不能跟踪进度&#xff1b; 质量追溯无法实现...... 等等一系列核心问题。 结合这些核心痛点&#xff0c;分享一套符合现在生产的智能化解决…

初阶结构体(超详解)

初阶结构体 1. 结构体的声明1.1 结构的基础知识1.2 结构的声明1.3 结构成员的类型1.4 结构体变量的初始化和定义 2. 结构体的访问3. 结构体传参 1. 结构体的声明 1.1 结构的基础知识 结构是一些值的集合&#xff0c;这些值称为成员变量。结构的每个成员可以是不同类型的变量 结…

cmake 配置Visual studio的调试命令

配置代码如截图&#xff1a; set_property(TARGET ${TARGET_NAME} PROPERTY VS_DEBUGGER_COMMAND "./consoleTest.exe") set_property(TARGET ${TARGET_NAME} PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "./config/labelDriver.cfg") set_propert…

服务机器人有哪些品类

服务机器人是指具备自主运动、感知环境、实现人机交互等能力的机器人&#xff0c;它可以被应用于不同的场景&#xff0c;如餐饮、医疗、物流等行业。根据其功能和应用场景的不同&#xff0c;服务机器人可以分为以下几类&#xff1a;1. 餐饮服务机器人 随着社会发展和人们需…

Jmeter阶梯式加压测试

熟悉阿里云性能测试PTS的都可以看到压测配置设置如下图&#xff0c;相比Jmeter简单的线程设置&#xff0c;要合理更直观。 但是我们会去研究&#xff0c;性能测试中&#xff0c;有时需要模拟一种实际生产中经常出现的情况&#xff0c; 即&#xff1a;从某个值开始不断增加压力…

IC秋招| 秋招怎么做准备,这份攻略请收下!

近期大家关注的就是秋招了&#xff0c;如今一些企业已经开启了提前批招聘&#xff0c;不少同学已经投递了简历&#xff0c;但内心还是非常焦虑&#xff0c;那么今年的秋招到底该如何准备呢&#xff1f; 简历投递思路建议 刚开始对大厂没有把握的话&#xff0c;可以先约初创或…

redis安装,开启自启动(Windows)

1、下载redis包 Releases tporadowski/redis GitHub 2、配置环境变量 path中添加redis解压后的路径&#xff1b; 3、配置文件修改 注释掉 bind 127.0.0.1 使其他ip可以远程访问&#xff1b; 修改redis密码 4、启动Redis服务 redis-server.exe --service-install redis.w…

百度地图点标记加调用

先看效果 PHP代码 <?phpnamespace kds_addons\edata\controller;use think\addons\Controller; use think\Db;class Maps extends Controller {// 经纬度计算面积function calculate_area($points){$totalArea 0;$numPoints count($points);if ($numPoints > 2) {f…

React组件进阶之children属性,props校验与默认值以及静态属性static

React组件进阶之children属性,props校验与默认值以及静态属性static 一、children属性二、props校验2.1 props说明2.2 prop-types的安装2.3 props校验规则2.4 props默认值 三、静态属性static 一、children属性 children 属性&#xff1a;表示该组件的子节点&#xff0c;只要组…

Java集合详解

Java集合详解 一、基本概要1.什么是集合2.常见的集合有哪些 二、基本知识1.集合框架底层数据结构1.1 Collection1.2 Map 2.线程安全的集合 三、集合具体讲解0.前沿知识0. ❤关于Iterator 迭代器1.Iterator迭代器是什么&#xff1f;用来干什么&#xff1f;&#xff08;用来遍历集…

Node.js之express框架学习心得

Node.js&#xff1a;颠覆传统的服务器端开发 Node.js是基于Chrome V8引擎构建的JavaScript运行时&#xff0c;它采用了完全不同的开发模型。Node.js使用事件驱动和非阻塞I/O的方式处理请求&#xff0c;通过单线程和异步机制&#xff0c;实现高效的并发处理。这意味着在Node.js中…