数据结构_Java_基于 线性表-单链表的初始化、逆序、去重、非递减序列的合并(开辟新链表先整体插入一个链表全部元素,再遍历另外一个链表寻找合适位置插入 、开辟新链表实现舍弃原链表)等操作实现
写在前面
不久前学习了数据结构线性表-数组-链表的相关知识,用C/C++语言实现了 单链表的系列相关操作 。见往期博客:
数据结构实验2_C语言_基于顺序表的非递减有序表的合并、线性表元素的增、删、改、查(while +switch + 功能函数)+后续改进优化
数据结构实验3_C语言_基于单链表的实现、单链表元素的逆序(while + switch + 功能函数)
课堂上老师提到实现不同操作往往有不同的方法,像
- 实现链表元素逆序
- 参考上面实验3采用的是 :遍历旧,头插新 的方法
- 本篇采用的是 :遍历修改当前节点的
next
的方法 - …
- 实现两链表非递减序列合并
- 参考上面实验2采用的是 :课本上的
三个while()
实现非递减数组合并 - 本篇采用的是: 先插入一个链表全部,然后遍历另外一个链表找合适位置插入
- 参考上面实验2采用的是 :课本上的
- 实现链表元素去重
- 参考上面实验2(数组)采用的是 :重复 元素后的元素 整体前覆盖的方法
- 本篇采用的是 :链表的删除重复节点
- …
为了进一步巩固知识,练习Java,所以使用Java实现一个简单的 单链表小操作,内容含括:
- 初始化头结点
- 初始化链表元素(读入数据采用:字符串–>字符串数组(正则分割)—>字符串数组---->
string
数据类型转化int
) - 链表元素逆置(超详细图解)
- 链表元素去重
- 两非递减链表的合并
- 链表元素打印(
for(长度控制)
、while(指针控制)
)- 含头结点的打印
- 不含头结点的打印
注意:
处于菜鸡级别的我写的代码可能不是那么完美,希望多多包涵,大佬希望能不吝赐教~~(抱拳)
虽热我走的很慢,但我仍在前进!
开始
开发环境:IDEA
程序运行截图
程序整体运行流程:
- 提示输入链表元素的个数(需要初始化的链表为 链表1 、链表2 )
- 初始化链表1(最好递减序列输入,因为后面只对链表1的 元素逆序、去重,方便实现后面 非递减序列的合并)
- 初始化链表2(非递减序列输入)
- 打印输出链表1、链表2
- 打印输出逆序后的链表1
- 打印输出去重后的链表1
- 打印合并后的链表
注意:对于链表逆置、非递减序列合并后面会详细分析代码实现
因为链表1开始逆置的时候删除了头结点,而逆置后没有头结点了,我这里另写了一种打印方法(一共三种)
printElem()
printElemByPointer()
printElemOtherWay()
一、源代码
- Demo1_MyListNode节点类
package one.test.list;public class Demo1_MyListNode {int var;Demo1_MyListNode next = null;Demo1_MyListNode(){};Demo1_MyListNode(int var){this.var = var;}}
- Demo1_ListBaseOperate功能操作类
package one.test.list;import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;public class Demo1_ListBaseOperate {public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("请输入你要初始化的链表元素的个数:");int length = sc.nextInt();//0. 创建头结点1,2Demo1_MyListNode touNode1 = new Demo1_MyListNode(length);Demo1_MyListNode touNode2 = new Demo1_MyListNode((length));//1. 初始化元素System.out.println("初始化链表1:");CreateList(touNode1);System.out.println("初始化链表2:");CreateList(touNode2);//5. 打印输出元素(有头结点的打印)System.out.println("正常顺序的链表");System.out.println("======================");printElem(touNode1);printElem(touNode2);System.out.println("======================");//2. 、 6.链表元素逆置、打印(无头结点的打印)Demo1_MyListNode reverseHead = ReverseList(touNode1);System.out.println("链表1逆序后为:");printElemOtherWay(reverseHead);//printElemByPointer(reverseHead);System.out.println("======================");//4. 链表元素去重DeleteSameElem(reverseHead);System.out.println("======================");//5. 链表合并Demo1_MyListNode heBingNode = HeBingLianBiao(reverseHead,touNode2);System.out.println("非递减序列合并的链表:");printElemByPointer(heBingNode);//printElemOtherWay(heBingNode);}//1 . 初始化链表插入元素public static void CreateList(Demo1_MyListNode L){Scanner sc = new Scanner(System.in);System.out.println("请输入你要插入的元素值:");//开始指向头结点的pDemo1_MyListNode p = L;String elem_str = sc.nextLine();String[] elem_str_arr = elem_str.split("\\s+");for(int i = 1;i<=L.var;i++){//创建新节点,接受元素值Demo1_MyListNode ElemNode = new Demo1_MyListNode((Integer.parseInt(elem_str_arr[i -1])));//设置指针用每次指向新节点Demo1_MyListNode pNewElem = ElemNode;//新节点放到头结点指针后面p.next = pNewElem;//新节点的next设置为nullpNewElem.next = null;//保证链表指针指向最后一个节点p = p.next;}}//2. 链表元素逆置public static Demo1_MyListNode ReverseList(Demo1_MyListNode L){//逆置后的头指针Demo1_MyListNode pre = null;//移动的指针Demo1_MyListNode p = null;//去掉头结点,否则待会输出,麻烦L = L.next;while(L != null){//p总是在最前面p = L.next;//L总是在中间,逆序指向上一个节点L.next = pre;//pre后移pre = L;//L后移L = p;}return pre;}//3. 链表合并(先全部插入一个,然后再将另一个表的的元素比较插入)public static Demo1_MyListNode HeBingLianBiao(Demo1_MyListNode L1,Demo1_MyListNode L2) {//L1为逆序去重后的链表1,无头结点//L2为链表2//创建合并链表Demo1_MyListNode head = new Demo1_MyListNode();//合并链表需要指针Demo1_MyListNode p_He = head;//先把L1的所有元素插入while (L1.next != null) {p_He.next = L1;L1 = L1.next;p_He = p_He.next;}//p_He重新指向 合并链表的头结点p_He = head;//p_L2指向 L2第一个节点,L2有头结点Demo1_MyListNode p_L2 = L2.next;//q_L2 指向插入 节点的下一个节点Demo1_MyListNode q_L2 = p_L2;while (p_L2.next != null) {//直到元素插入,循环结束q_L2 = p_L2.next;while (p_He.next != null) {if (p_L2.var < p_He.var) {p_L2.next = p_He.next;p_He.next = p_L2;break;}//插入到合适的位置else if (p_L2.var >= p_He.var && p_L2.var < p_He.next.var) {p_L2.next = p_He.next;p_He.next = p_L2;break;} else {p_He = p_He.next;}}if (p_He.next == null) {//插入到合并链表的最后p_He.next = p_L2;break;}p_L2 = q_L2;}return head;}//4.链表元素去重public static void DeleteSameElem(Demo1_MyListNode L){Demo1_MyListNode p = L;while(p.next.next != null){if(p.var == p.next.var){p.next = p.next.next;}else{//注意要放到else里面,否则出现3个重复的只能去掉一个p = p.next;}}System.out.println("链表1去重之后:");printElemOtherWay(L);}// 5. 打印链表元素(正序有头结点的打印)private static void printElem(Demo1_MyListNode L) {Demo1_MyListNode p = L;System.out.println("元素为:");for (int i = 1;i<=L.var;i++){p = p.next;System.out.print(p.var + " ");}System.out.println();}//6. 打印链表元素另一种方法(逆置后无头结点的打印)private static void printElemOtherWay(Demo1_MyListNode pre) {Demo1_MyListNode p = pre;System.out.println("元素为:");//注意这里是p.next而不是p.next.next,因为下面最后执行了p = p.next//处在逆序链表结尾的头结点不需要打印while(p!= null){System.out.print(p.var + " ");p = p.next;}System.out.println();}//7. 打印链表,不用链表长度,用指针private static void printElemByPointer(Demo1_MyListNode L){Demo1_MyListNode p = L.next;while(p!=null){System.out.print(p.var + " ");p = p.next;}}}
二、功能实现代码分析
- 逆置链表元素
如果只看代码还不是理解,请看下面的图解(不会画图的程序员不是一个好博主~~O(∩_∩)O哈哈~)
注意:这里的图 头结点还没删除,可以L = L.next删除,下面更方便
看了图解之后是不是清晰了许多呢
这里还需要注意一个问题(就是逆置后的链表,是没有头结点的,因为头结点在尾部,等会我们打印的时候也要注意哦)
- 非递减序列的合并
说明:
参数L1
—>传入原始L1经逆序、去重后的新链表,待会先全部插入带合并链表中
参数L2
---->输入的非递减序链表L2
p_Head
—>开始指向合并链表的头结点
p_L1
---->指向逆序、去重后的L1第一个节点(无头结点)
p_L2
—>指向待插入链表L2的第一个节点
q_L2
---->每次循环开始(节点还未断开)时,指向p_L2
当前节点的下一个节点,本次循环结束之前(p_L2
指向的节点已经断开
插入),便于p_L2
找到逻辑下一个节点,从而一次遍历插入到合并链表中
然后
嵌套循环插入L2的各节点。外层循环控制遍历待插入的节点
内层循环控制 插入的位置
所谓合适的位置:
- 合适的中间位置:
p_L2
指向的当前节点值 大于p_He
指向的合并链表 当前节点,小于p_He.next
的节点值(找不到就移动p_Head) - 合并链表的尾部:一直移动
p_Head
指向null
,发现还是找不到,说明要把p_L2
指向的节点插入到合并链表的最后
最后
直到全部插入,循环结束,返回合并链表的头指针
三、NK-有序链表合并
之后遇到NK上面一道 合并有序链表的 题,本着老思路去写,但是部分通过
(因为题目测试用的链表可以为空,或者两个链表只有一个节点),后来改了之后时间复杂度太高,不同过,看了一种题解,
思路是类似数据结构课本上的 3个while()
方法(直接移动原链表的指针进行值比较插入,舍弃原链表)
题目描述
将两个有序的链表合并为一个新链表,要求新的链表是通过拼接两个链表的节点来生成的。
示例1
- 输入
{1},{}
- 输出
{1}
示例2
输入
{1},{1}
输出
{1,1}
运行超时代码
import java.util.*;/** public class ListNode {* int val;* ListNode next = null;* }*/public class Solution {/*** * @param l1 ListNode类 * @param l2 ListNode类 * @return ListNode类*/public ListNode mergeTwoLists (ListNode l1, ListNode l2) {// write code hereListNode p_l1 = l1;ListNode p_next = l1;ListNode q_l2 = l2;//l1 没节点if(p_l1 == null){return q_l2;}//l2 没节点if(q_l2 == null){return p_l1;}// l1 和 l2 只有一个节点if(p_l1.next == null && q_l2.next == null){if(p_l1.val <= q_l2.val){p_l1.next = q_l2;l2 = p_l1;}else{q_l2.next = p_l1;}}//遍历 l1 的节点插入到 l2while(p_l1.next != null){//前指针方便 找到当前节点的下一个节点p_next = p_l1.next;while(q_l2.next != null){//插入到 l2 第一个节点if(p_l1.val < q_l2.val){p_l1.next = q_l2;l2 = p_l1;break;}//插入到 l2 中间位置else if(p_l1.val >= q_l2.val && p_l1.val <= q_l2.next.val){p_l1.next = q_l2.next;q_l2.next = p_l1;break;}//接着找中间 的位置,直到最后一个节点else{q_l2 = q_l2.next;}//若 没有合适的位置,就插入到末尾}if(q_l2.next == null){q_l2.next = p_l1;}//待插入的下一个节点p_l1 = p_next;}return l2;}
}
- 题解代码
舍弃原链表,类似3while算法
import java.util.*;/** public class ListNode {* int val;* ListNode next = null;* }*/public class Solution {/*** * @param l1 ListNode类 * @param l2 ListNode类 * @return ListNode类*/public ListNode mergeTwoLists (ListNode l1, ListNode l2) {// write code here//设置新的头结点,方便操作ListNode head = new ListNode(0);ListNode p = head;//l1 和 l2 都有节点while(l1 != null && l2 != null){//插入 l1 链表当前指向节点if(l1.val <= l2.val){p.next = l1;l1 = l1.next;}//插入l2 链表当前指向节点else{p.next = l2;l2 = l2.next;}//插入一个节点后,p指针后移p = p.next;}// l1还有剩余节点没插入,或者l2链表不含节点if(l1 != null){p.next = l1;}// l2还有剩余节点,或者l21链表不含节点if(l2 != null){p.next = l2;}return head.next;}}
数据结构_Java_基于 线性表-单链表的初始化、逆序、去重、非递减序列的合并(开辟新链表先整体插入一个链表全部元素,再遍历另外一个链表寻找合适位置插入 、开辟新链表实现舍弃原链表)等操作实现相关推荐
- 数据结构实验--基于线性表的图书信息管理系统
本文是依据数据结构习题解析与实验指导(李冬梅)一书中的第一个实验–基于线性表的图书信息管理系统所写的. 之所以写这个,是因为这个实验不仅涉及到线性表的结构设计,还包括一些线性表的基本操作,个人认为,做 ...
- python的线性链表_Python线性表——单链表-阿里云开发者社区
Python线性表--单链表 线性表简介 线性表是一种线性结构,它是由零个或多个数据元素构成的有限序列.线性表的特征是在一个序列中,除了头尾元素,每个元素都有且只有一个直接前驱,有且只有一个直接后继, ...
- 数据结构 基于线性表的图书信息管理
数据结构 基于线性表的图书信息管理 实验前的准备 IDE的选择 C语言中指针与结构体 实验目的 实验内容 1.基于顺序存储结构的图书信息表的创建和输出 代码 实验中遇到的问题 ① 实验中遇到的问题 ② ...
- 数据结构实验1《基于线性表的图书管理系统》
数据结构实验1<基于线性表的图书管理系统> (visual studio 2019可运行) 输入及输出要求见<数据结构C语言(第二版)>严蔚敏版 [本文仅用于啥都看不懂还想交作 ...
- Algorithms_基础数据结构(02)_线性表之链表_单向链表
文章目录 大纲图 链表的经典面试题目 如何设计一个LRU缓存淘汰算法 约瑟夫问题 顺序表VS 链表 链表的定义 链表的特点 常见的链表结 单向链表 单向链表的查找 单向链表的插入 头插 尾部插入 中间 ...
- 线性表(单链表)实验
一.实验目的 1.线性表(LINE)的概念:数据元素之间存在着线性关系. 2.线性表的顺序表示和实现. 3.线性表的链式表示和实现. 4.线性表的基本操作:初始化.插入.修改.删除.遍历. 二.实验内 ...
- Algorithms_基础数据结构(04)_线性表之链表_单向循环链表约瑟夫环问题
文章目录 大纲图 链表的经典面试题目 如何设计一个LRU缓存淘汰算法 约瑟夫问题 结构 分析 大纲图 链表的经典面试题目 如何设计一个LRU缓存淘汰算法 tip:单向链表 约瑟夫问题 N个人围成一圈, ...
- C语言数据结构-第二章线性表-电大
第二章线性表--内容简介 本章将进入线性结构的学习. 线性结构是最简单.最常用的一种数据结构. 本章将学习线性表的定义.顺序和链式两种存储方式及相应存储结构上的运算实现.通过典型示例训练,掌握线性表的 ...
- 数据结构复习题(线性表)
数据结构复习题(线性表) 线性表 选择题 填空题 判断题 解答题 顺序表的插入和删除 单链表的插入与删除,创建 线性表 选择题 用单链表方式存储的线性表,存储每个节点需要两个域,一个是数据域,另一个是 ...
最新文章
- Bi-level error correction for PacBio long reads. PacBio长读数的两级纠错
- vim在每行行首或行尾添加/删除内容
- 1分钟深入了解CSS3的动画属性animation
- MPI程序例子 test_8_1_2.c -- 对等模式的MPI程序,Jacobi迭代 (MPI_Send、MPI_Recv)
- linux 下 qserialport waitforreadyread_北师大版初中数学八年级(下)第二章第一节不等关系(精品)...
- jquery之val()和attr(value)
- python连接pymysql主机目标无响应_Python 解析pymysql模块操作数据库的方法
- Express4.x API (一):application (译)
- 如何计算吃鸡游戏的物理碰撞?
- 【深度优先搜索】复原IP地址
- uva 10105(数论)
- 带宽与码元的关系_带宽和传输速率的关系是什么?
- Tech Blog by Eason!
- FrameMaker 格式的本地化流程
- 1.7.1 计算机网络体系结构的形成
- Bigwig 可视化用 tackPlotR 试试看?
- 51单片机仿真——中断系统(2)
- wordart-在线生成要想的图片做为报告的门面
- 计算机版初中语文课文原文,初中语文课文蝉原文
- 创客学院知识巩固-01C语言回顾
热门文章
- 十五、Fluent湿空气模拟-组分输运模型
- BI_开发_问题:ORA-26002: Table DWH.W_XACT_TYPE_D has index defined upon it.
- Redis的持久化机制、过期策略、淘汰策略
- 有用的“歪门邪道”-设计模式
- 在文件原位置修改文件内容
- 如何读到一个文件的最后更新日期和时间
- 天平游码读数例题_天平游码读数
- 穿山甲别于传统广告联盟,造势创建新角色
- Python 之selenium+phantomJS斗鱼抓取案例
- Java用最少代码实现五子棋-玩家对战模式-人机对战模式-电脑策略对战