写在前面

不久前学习了数据结构线性表-数组-链表的相关知识,用C/C++语言实现了 单链表的系列相关操作 。见往期博客:

数据结构实验2_C语言_基于顺序表的非递减有序表的合并、线性表元素的增、删、改、查(while +switch + 功能函数)+后续改进优化

数据结构实验3_C语言_基于单链表的实现、单链表元素的逆序(while + switch + 功能函数)

课堂上老师提到实现不同操作往往有不同的方法,像

  • 实现链表元素逆序

    1. 参考上面实验3采用的是 :遍历旧,头插新 的方法
    2. 本篇采用的是 :遍历修改当前节点的 next的方法
  • 实现两链表非递减序列合并
    1. 参考上面实验2采用的是 :课本上的三个while() 实现非递减数组合并
    2. 本篇采用的是: 先插入一个链表全部,然后遍历另外一个链表找合适位置插入
  • 实现链表元素去重
    1. 参考上面实验2(数组)采用的是 :重复 元素后的元素 整体前覆盖的方法
    2. 本篇采用的是 :链表的删除重复节点

为了进一步巩固知识,练习Java,所以使用Java实现一个简单的 单链表小操作,内容含括:

  1. 初始化头结点
  2. 初始化链表元素(读入数据采用:字符串–>字符串数组(正则分割)—>字符串数组---->string数据类型转化int
  3. 链表元素逆置(超详细图解)
  4. 链表元素去重
  5. 两非递减链表的合并
  6. 链表元素打印(for(长度控制)while(指针控制))
    • 含头结点的打印
    • 不含头结点的打印

注意:

处于菜鸡级别的我写的代码可能不是那么完美,希望多多包涵,大佬希望能不吝赐教~~(抱拳)

虽热我走的很慢,但我仍在前进!


开始

开发环境:IDEA

程序运行截图

程序整体运行流程:

  1. 提示输入链表元素的个数(需要初始化的链表为 链表1 、链表2 )
  2. 初始化链表1(最好递减序列输入,因为后面只对链表1的 元素逆序、去重,方便实现后面 非递减序列的合并)
  3. 初始化链表2(非递减序列输入)
  4. 打印输出链表1、链表2
  5. 打印输出逆序后的链表1
  6. 打印输出去重后的链表1
  7. 打印合并后的链表

注意:对于链表逆置、非递减序列合并后面会详细分析代码实现

因为链表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_基于 线性表-单链表的初始化、逆序、去重、非递减序列的合并(开辟新链表先整体插入一个链表全部元素,再遍历另外一个链表寻找合适位置插入 、开辟新链表实现舍弃原链表)等操作实现相关推荐

  1. 数据结构实验--基于线性表的图书信息管理系统

    本文是依据数据结构习题解析与实验指导(李冬梅)一书中的第一个实验–基于线性表的图书信息管理系统所写的. 之所以写这个,是因为这个实验不仅涉及到线性表的结构设计,还包括一些线性表的基本操作,个人认为,做 ...

  2. python的线性链表_Python线性表——单链表-阿里云开发者社区

    Python线性表--单链表 线性表简介 线性表是一种线性结构,它是由零个或多个数据元素构成的有限序列.线性表的特征是在一个序列中,除了头尾元素,每个元素都有且只有一个直接前驱,有且只有一个直接后继, ...

  3. 数据结构 基于线性表的图书信息管理

    数据结构 基于线性表的图书信息管理 实验前的准备 IDE的选择 C语言中指针与结构体 实验目的 实验内容 1.基于顺序存储结构的图书信息表的创建和输出 代码 实验中遇到的问题 ① 实验中遇到的问题 ② ...

  4. 数据结构实验1《基于线性表的图书管理系统》

    数据结构实验1<基于线性表的图书管理系统> (visual studio 2019可运行) 输入及输出要求见<数据结构C语言(第二版)>严蔚敏版 [本文仅用于啥都看不懂还想交作 ...

  5. Algorithms_基础数据结构(02)_线性表之链表_单向链表

    文章目录 大纲图 链表的经典面试题目 如何设计一个LRU缓存淘汰算法 约瑟夫问题 顺序表VS 链表 链表的定义 链表的特点 常见的链表结 单向链表 单向链表的查找 单向链表的插入 头插 尾部插入 中间 ...

  6. 线性表(单链表)实验

    一.实验目的 1.线性表(LINE)的概念:数据元素之间存在着线性关系. 2.线性表的顺序表示和实现. 3.线性表的链式表示和实现. 4.线性表的基本操作:初始化.插入.修改.删除.遍历. 二.实验内 ...

  7. Algorithms_基础数据结构(04)_线性表之链表_单向循环链表约瑟夫环问题

    文章目录 大纲图 链表的经典面试题目 如何设计一个LRU缓存淘汰算法 约瑟夫问题 结构 分析 大纲图 链表的经典面试题目 如何设计一个LRU缓存淘汰算法 tip:单向链表 约瑟夫问题 N个人围成一圈, ...

  8. C语言数据结构-第二章线性表-电大

    第二章线性表--内容简介 本章将进入线性结构的学习. 线性结构是最简单.最常用的一种数据结构. 本章将学习线性表的定义.顺序和链式两种存储方式及相应存储结构上的运算实现.通过典型示例训练,掌握线性表的 ...

  9. 数据结构复习题(线性表)

    数据结构复习题(线性表) 线性表 选择题 填空题 判断题 解答题 顺序表的插入和删除 单链表的插入与删除,创建 线性表 选择题 用单链表方式存储的线性表,存储每个节点需要两个域,一个是数据域,另一个是 ...

最新文章

  1. Bi-level error correction for PacBio long reads. PacBio长读数的两级纠错
  2. vim在每行行首或行尾添加/删除内容
  3. 1分钟深入了解CSS3的动画属性animation
  4. MPI程序例子 test_8_1_2.c -- 对等模式的MPI程序,Jacobi迭代 (MPI_Send、MPI_Recv)
  5. linux 下  qserialport waitforreadyread_北师大版初中数学八年级(下)第二章第一节不等关系(精品)...
  6. jquery之val()和attr(value)
  7. python连接pymysql主机目标无响应_Python 解析pymysql模块操作数据库的方法
  8. Express4.x API (一):application (译)
  9. 如何计算吃鸡游戏的物理碰撞?
  10. 【深度优先搜索】复原IP地址
  11. uva 10105(数论)
  12. 带宽与码元的关系_带宽和传输速率的关系是什么?
  13. Tech Blog by Eason!
  14. FrameMaker 格式的本地化流程
  15. 1.7.1 计算机网络体系结构的形成
  16. Bigwig 可视化用 tackPlotR 试试看?
  17. 51单片机仿真——中断系统(2)
  18. wordart-在线生成要想的图片做为报告的门面
  19. 计算机版初中语文课文原文,初中语文课文蝉原文
  20. 创客学院知识巩固-01C语言回顾

热门文章

  1. 十五、Fluent湿空气模拟-组分输运模型
  2. BI_开发_问题:ORA-26002: Table DWH.W_XACT_TYPE_D has index defined upon it.
  3. Redis的持久化机制、过期策略、淘汰策略
  4. 有用的“歪门邪道”-设计模式
  5. 在文件原位置修改文件内容
  6. 如何读到一个文件的最后更新日期和时间
  7. 天平游码读数例题_天平游码读数
  8. 穿山甲别于传统广告联盟,造势创建新角色
  9. Python 之selenium+phantomJS斗鱼抓取案例
  10. Java用最少代码实现五子棋-玩家对战模式-人机对战模式-电脑策略对战