目录

  • 一、单链表的头插法:
  • 二、单链表的尾插法:
  • 三、单链表顺序添加:
  • 四、按照值查找节点:
  • 五、删除节点:
  • 六、修改节点:
  • 七、求单链表的表长:
  • 最后的总代码:
  • 单链表常见面试题:

一、单链表的头插法:

头插法原理图:

代码演示头插法:

package com.fan.linkedlist;public class SingleLInkedListDemo3 {public static void main(String[] args) {SingleLInkedList3 singlelist3 = new SingleLInkedList3();System.out.println(singlelist3.headInsert(1));System.out.println(singlelist3.headInsert(2));System.out.println(singlelist3.headInsert(3));System.out.println("显示链表:");singlelist3.show();//测试尾插法1:向单链表增加数据System.out.println("\n测试尾插法1:");SingleLInkedList3 singlelist4 = new SingleLInkedList3();System.out.println(singlelist4.tailInsert1(4));System.out.println(singlelist4.tailInsert1(5));System.out.println(singlelist4.tailInsert1(6));singlelist4.show();//测试尾插法2:向单链表增加数据System.out.println("\n测试尾插法2:");SingleLInkedList3 singlelist5 = new SingleLInkedList3();System.out.println(singlelist5.tailInsert2(7));System.out.println(singlelist5.tailInsert2(8));System.out.println(singlelist5.tailInsert2(9));singlelist5.show();}
}
//2.创建链表类,并初始化头结点/尾结点,设置其的指针域为空.
class SingleLInkedList3{//链表带泛型//一个单链表是由多个节点构成的。这里我们设置头节点和尾部节点//声明头节点,并设置其指针域为空即headNode --->  nullNode3 headNode = new Node3();//声明尾部节点,用来演示尾插法而设置的变量Node3 tailNode = new Node3();public Node3 getHeadNode() {return headNode;}public void setHeadNode(Node3 headNode) {this.headNode = headNode;}public Node3 getTailNode() {return tailNode;}public void setTailNode(Node3 tailNode) {this.tailNode = tailNode;}//使用空的构造方法创建单链表,当一个空链表创建好了之后就要有头或者尾节点//此构造方法很重要public SingleLInkedList3() {//初始化头节点的next指针域为空,并设置其指针域为空即headNode --->  nullheadNode.setNext(null);//一个空链表的头节点是指向null的//初始化尾节点的next指针域也为空,采用头插法就没必要设置tailNodetailNode.setNext(null);//headNode永远存储第一个节点的地址,tailNode永远存储最后一个节点的地址headNode = tailNode ;//也为了show方法的遍历}//头插法,即头节点不动,其后的指针每次进行拆散,并将新节点插入到头节点紧邻后边/*头插法一般也用于单链表模拟栈,我们用头插法能实现先入后出*//*向单链表增加数据*/public boolean headInsert(Object obj){Node3 newNode = new Node3(obj);//将数据封装成一个新节点newNode.setNext(headNode.getNext());//设置新节点的后驱节点为 头节点的下一个节点headNode.setNext(newNode);//设置新节点的前驱节点为 头节点,即头节点不动//如果头节点紧邻后是新节点,证明头插入成功return headNode.getNext() == newNode;}//尾插法  ====第一种实现:使用从头节点遍历找尾节点并插入===/*向单链表增加数据*/public boolean tailInsert1(Object obj){Node3 newNode = new Node3(obj);Node3 curr = headNode;//临时节点从头节点开始遍历,while(true){if(curr.getNext() == null){break;//到了链表结尾}curr = curr.getNext();//临时节点后移}//end-while//出循环后就证明到了链表结尾,直接添加新节点,curr此时指向了最后一个有效节点curr.setNext(newNode);newNode.setNext(null);return newNode.getNext() == null;}//尾插法====第二种实现,使用尾节点移动来实现public boolean tailInsert2(Object obj){Node3 newNode = new Node3(obj);//1.将尾指针的指针域指向 刚刚插入的新节点newNodetailNode.setNext(newNode);//刷新尾节点,现在newNode变成了最后一个元素了,也就是新的尾节点//2.tailNode永远存储最后一个节点tailNode = newNode;//尾节点指向新添加的节点,即尾节点后移,类似于i++//将最终的尾节点指针域赋值为空tailNode.setNext(null);return tailNode.getNext()==null;}//链表元素的显示public void show(){//定义一个临时变量curr来遍历链表,不能使用头节点,因为头节点不能动Node3 curr = headNode.getNext();//curr指向头节点下一个,或者说将头节点地址赋值给curr临时节点while(true){if(curr == null){//下一个有效元素位空,则到了链表的结尾break;}System.out.print(curr+"\t-->");//打印当前有效节点curr = curr.getNext();//指针后移,相当于i++}}//链表元素的显示}
//1.创建节点类,也可以将此类设置成内部类
class Node3{//数据域,可以是多个数据如name,id,age等private Object object;////指针域,单链表有数据域和next指针这两项private Node3 next;//指向下驱节点public Node3(Object object) {this.object = object;}public Node3() {}public Object getObject() {return object;}public void setObject(Object object) {this.object = object;}public Node3 getNext() {return next;}public void setNext(Node3 next) {this.next = next;}@Overridepublic String toString() {return "Node3{" +"object=" + object +'}';}
}

测试结果:

二、单链表的尾插法:

尾插法: 尾插法相对于头插法有些许不同 因为要返回头 头不能动 所以需要一个tailNode来记录最后一个值 tailNode右移

尾插法原理图:
开始tailNode–>null是指向null的。


代码:

   //尾插法  ====第一种实现:使用从头节点遍历找尾节点并插入===/*向单链表增加数据*/public boolean tailInsert1(Object obj){Node3 newNode = new Node3(obj);Node3 curr = headNode;//临时节点从头节点开始遍历,while(true){if(curr.getNext() == null){break;//到了链表结尾}curr = curr.getNext();//临时节点后移}//end-while//出循环后就证明到了链表结尾,直接添加新节点,curr此时指向了最后一个有效节点curr.setNext(newNode);newNode.setNext(null);return newNode.getNext() == null;}//尾插法====第二种实现,使用尾节点移动来实现public boolean tailInsert2(Object obj){Node3 newNode = new Node3(obj);//1.将尾指针的指针域指向 刚刚插入的新节点newNodetailNode.setNext(newNode);//刷新尾节点,现在newNode变成了最后一个元素了,也就是新的尾节点//2.tailNode永远存储最后一个节点tailNode = newNode;//尾节点指向新添加的节点,即尾节点后移,类似于i++//将最终的尾节点指针域赋值为空tailNode.setNext(null);return tailNode.getNext()==null;}

测试代码:

public class SingleLInkedListDemo3 {public static void main(String[] args) {SingleLInkedList3 singlelist3 = new SingleLInkedList3();System.out.println(singlelist3.headInsert(1));System.out.println(singlelist3.headInsert(2));System.out.println(singlelist3.headInsert(3));System.out.println("显示链表:");singlelist3.show();//测试尾插法1:向单链表增加数据System.out.println("\n测试尾插法1:");SingleLInkedList3 singlelist4 = new SingleLInkedList3();System.out.println(singlelist4.tailInsert1(4));System.out.println(singlelist4.tailInsert1(5));System.out.println(singlelist4.tailInsert1(6));singlelist4.show();//测试尾插法2:向单链表增加数据System.out.println("\n测试尾插法2:");SingleLInkedList3 singlelist5 = new SingleLInkedList3();System.out.println(singlelist5.tailInsert2(7));System.out.println(singlelist5.tailInsert2(8));System.out.println(singlelist5.tailInsert2(9));singlelist5.show();}
}

测试结果:

总结头插法和尾插法:

三、单链表顺序添加:

需求,我们有一批购房的摇号者,我们让摇号者的编号小的越先获取购房资格,请乱序添加5个摇号者的编号,添加到链表中后是从小到大排好序的。

分析:单链表的按照次序添加,区别于头插法和尾插法:

  //按照编号顺序添加public void addByOrder(ConsumerNode newNode){ConsumerNode curr = headNode;//头节点不能动,所以设置临时节点boolean flag = false;//默认编号不存在while(true){//遍历到链表结尾的时候if(curr.getNext() == null){break;}//判断编号的插入位置if(newNode.getNo() < curr.getNext().getNo()){break;//头插}else if(newNode.getNo() == curr.getNext().getNo()){flag = true;//编号相同的特殊情况,单独处理break;}curr = curr.getNext();}if(!flag){//当编号不存在的时候我们才添加newNode.setNext(curr.getNext());curr.setNext(newNode);}else{System.out.println("编号相同,不能插入---");}}

四、按照值查找节点:

//根据数据域编号查找该节点的所有信息public void findByNo(Integer key){ConsumerNode curr =headNode;boolean flag =false;while(true){if(curr.getNext() == null){//到链表结尾,退出循环break;}if(curr.getNext().getNo() == key){flag = true;//找到查找的节点了,退出break;}curr = curr.getNext();//临时节点后移进行遍历}if(flag){System.out.println(curr.getNext());}else{System.out.println("没有找到要查找的节点信息----");}}

五、删除节点:

//删除某一个节点,按照编号public void delByNo(Integer no){ConsumerNode curr = headNode;boolean flag = false;//设置是否找到要删除的节点while(true){//需要判断是否到链表的结尾处if(curr.getNext() == null){break;}if(curr.getNext().getNo() == no){flag = true;break;}curr = curr.getNext();//没有找到的话,后移继续找}if(flag){curr.setNext(curr.getNext().getNext());}else{System.out.println("没有此节点要删除---");}}

六、修改节点:

    //修改某一个节点,根据节点编号,修改public void update(ConsumerNode newNode){//思路,就是替换编号 相同的节点,即插入新节点ConsumerNode curr = headNode;boolean flag = false;//设置是否找到要修改的节点while(true){//需要先判断是否到链表的结尾处if(curr.getNext() == null){break;//到链表的结尾}if(curr.getNext().getNo()== newNode.getNo()  ){flag = true;break;}curr = curr.getNext();}if(flag){newNode.setNext(curr.getNext().getNext());curr.setNext(newNode);}else{System.out.println("输入的编号没找到对应节点---");}}

七、求单链表的表长:

//获取链表的长度public int getSize(){int count = 0;ConsumerNode curr = headNode;while(true){if(curr.getNext() == null){break;}count++;curr = curr.getNext();}return count;}

最后的总代码:

package com.fan.linkedlist;public class SingleLinkedlistDemo4 {public static void main(String[] args) {//创建一个空链表ConsumerLinkedlist consumerLinkedlist = new ConsumerLinkedlist();/*consumerLinkedlist.addFirst(new ConsumerNode(1,"小一"));consumerLinkedlist.addFirst(new ConsumerNode(2,"小二"));consumerLinkedlist.addFirst(new ConsumerNode(3,"张三"));*//*consumerLinkedlist.addLast(new ConsumerNode(1,"小一"));consumerLinkedlist.addLast(new ConsumerNode(2,"小二"));consumerLinkedlist.addLast(new ConsumerNode(3,"张三"));consumerLinkedlist.addLast(new ConsumerNode(4,"李四"));*/consumerLinkedlist.addByOrder(new ConsumerNode(4,"小一"));consumerLinkedlist.addByOrder(new ConsumerNode(2,"小二"));consumerLinkedlist.addByOrder(new ConsumerNode(1,"张三"));consumerLinkedlist.addByOrder(new ConsumerNode(3,"李四"));consumerLinkedlist.addByOrder(new ConsumerNode(5,"李四"));System.out.println("显示添加后的顺序链表:");consumerLinkedlist.show();System.out.println("\n链表长度:"+ consumerLinkedlist.getSize());//consumerLinkedlist.delByNo(3);consumerLinkedlist.delByNo(11);System.out.println("删除后显示:");consumerLinkedlist.show();System.out.println("\n修改节点:===");consumerLinkedlist.update(new ConsumerNode(3,"我是大山"));//测试的此编号不存在consumerLinkedlist.show();System.out.println("\n查找节点========");//consumerLinkedlist.findByNo(8);consumerLinkedlist.findByNo(3);}
}
//链表类
class ConsumerLinkedlist{//一个单链表要有头节点或者尾节点private ConsumerNode headNode = new ConsumerNode();private ConsumerNode tailNode = new ConsumerNode();//构造方法public ConsumerLinkedlist(){headNode.setNext(null);tailNode.setNext(null);//头节点和尾节点开始时是重合的,都是指向null的//headNode永远存储第一个节点的地址,tailNode永远存储最后一个节点的地址headNode = tailNode ;//头尾重合,两个指针重合}//按照标号添加到链表中public void addFirst(ConsumerNode newNode){//头插法,不需要循环,头节点不动//注意,必须先处理新节点的后驱节点newNode.setNext(headNode.getNext());headNode.setNext(newNode);}//尾插法,还是头结点不动,尾节点移动public void addLast(ConsumerNode newNode){//注意,tailNode此时相当于一个临时的节点指针,相当一个指向节点的一个箭头/*  if(tailNode.getNext() == null){//直接添加新节点到尾节点的后边tailNode.setNext(newNode);//让尾节点成为最后一个节点tailNode = tailNode.getNext();//让尾节点的指针为nulltailNode.setNext(null);}*///直接添加新节点到尾节点的后边tailNode.setNext(newNode);tailNode = tailNode.getNext();//让尾节点成为最后一个节点tailNode.setNext(null);//让尾节点指向null}//按照编号顺序添加public void addByOrder(ConsumerNode newNode){ConsumerNode curr = headNode;//头节点不能动,所以设置临时节点boolean flag = false;//默认编号不存在while(true){//遍历到链表结尾的时候if(curr.getNext() == null){break;}//判断编号的插入位置if(newNode.getNo() < curr.getNext().getNo()){break;//头插}else if(newNode.getNo() == curr.getNext().getNo()){flag = true;//编号相同的特殊情况,单独处理break;}curr = curr.getNext();}if(!flag){//当编号不存在的时候我们才添加newNode.setNext(curr.getNext());curr.setNext(newNode);}else{System.out.println("编号相同,不能插入---");}}//删除某一个节点,按照编号public void delByNo(Integer no){ConsumerNode curr = headNode;boolean flag = false;//设置是否找到要删除的节点while(true){//需要判断是否到链表的结尾处if(curr.getNext() == null){break;}if(curr.getNext().getNo() == no){flag = true;break;}curr = curr.getNext();//没有找到的话,后移继续找}if(flag){curr.setNext(curr.getNext().getNext());}else{System.out.println("没有此节点要删除---");}}//修改某一个节点,根据节点编号,修改public void update(ConsumerNode newNode){//思路,就是替换编号 相同的节点,即插入新节点ConsumerNode curr = headNode;boolean flag = false;//设置是否找到要修改的节点while(true){//需要先判断是否到链表的结尾处if(curr.getNext() == null){break;//到链表的结尾}if(curr.getNext().getNo()== newNode.getNo()  ){flag = true;break;}curr = curr.getNext();}if(flag){newNode.setNext(curr.getNext().getNext());curr.setNext(newNode);}else{System.out.println("输入的编号没找到对应节点---");}}//根据数据域编号查找该节点的所有信息public void findByNo(Integer key){ConsumerNode curr =headNode;boolean flag =false;while(true){if(curr.getNext() == null){//到链表结尾,退出循环break;}if(curr.getNext().getNo() == key){flag = true;//找到查找的节点了,退出break;}curr = curr.getNext();//临时节点后移进行遍历}if(flag){System.out.println(curr.getNext());}else{System.out.println("没有找到要查找的节点信息----");}}//获取链表的长度public int getSize(){int count = 0;ConsumerNode curr = headNode;while(true){if(curr.getNext() == null){break;}count++;curr = curr.getNext();}return count;}//单链表的遍历public void show(){//判断链表是否为空,只有一个头节点的话直接结束if(headNode.getNext() == null){System.out.println("链表为空");return;}ConsumerNode curr = headNode.getNext();//从有效节点开始遍历while(true){if(curr == null){//到链表末尾时退出break;}System.out.print(curr+"-->");curr = curr.getNext();}}
}
//消费者节点,消费者将来需要被叫号排到链表中,可以用lambook
class ConsumerNode {//数据域private Integer no;private String name;//指针域,单链表只有一个next指针域,用于指向下一个节点private ConsumerNode next;//生成构造和set,get等public ConsumerNode(Integer no, String name) {this.no = no;this.name = name;}public ConsumerNode() {}public Integer getNo() {return no;}public void setNo(Integer no) {this.no = no;}public String getName() {return name;}public void setName(String name) {this.name = name;}public ConsumerNode getNext() {return next;}public void setNext(ConsumerNode next) {this.next = next;}@Overridepublic String toString() {return "ConsumerNode{" +"no=" + no +", name='" + name + '\'' +'}';}
}

单链表常见面试题:

单链表的反转:

    //单链表的反转,类似于头插法,返回一个新链表的头节点,不影响原链表结构public void resver(){ConsumerNode curr = headNode.getNext();//用于遍历的指针节点ConsumerNode temp = null;//后面用于存储curr的后驱节点的ConsumerNode newlinkedHead = new ConsumerNode();//循环拆解原链表,并拼接到新链表的头节点上if(curr.getNext() == null || curr.getNext().getNext() == null){return ;//只有一个节点或者空链表}while(true){if(curr == null){break;//到链表结尾}if(curr != null){//先将curr的下一个节点保存起来temp = curr.getNext();//设置curr的下一个节点不再是原先链表的下一个节点了,而是新链表头节点的下一个节点curr.setNext(newlinkedHead.getNext());//新节点的下一个节点就是currnewlinkedHead.setNext(curr);//让curr后移到原先链表的后一个节点curr = temp;//这个相当于原先的 curr = curr.getNext();}}//将新链表的所有节点穿到旧链表的头节点上,这样输出旧链表就已经反转了headNode.setNext(newlinkedHead.getNext());}

测试:

public class SingleLinkedlistDemo4 {public static void main(String[] args) {//创建一个空链表ConsumerLinkedlist consumerLinkedlist = new ConsumerLinkedlist();//添加顺序1->2->3->4->5consumerLinkedlist.addLast(new ConsumerNode(1,"小一"));consumerLinkedlist.addLast(new ConsumerNode(2,"小二"));consumerLinkedlist.addLast(new ConsumerNode(3,"张三"));consumerLinkedlist.addLast(new ConsumerNode(4,"李四"));consumerLinkedlist.addLast(new ConsumerNode(5,"李四"));System.out.println("\n反转链表:--");consumerLinkedlist.resver();consumerLinkedlist.show();}
}

对于从尾部到头部打印单链表,可以先反转,后调用show方法即可;

Java单链表头插法和尾插法以及增删改查方法相关推荐

  1. 单链表头插法和尾插法

    1.头插法 头插法:每次把新节点插入到头节点之后,创建的单链表和数据输入顺序相反. 防止单链表是空的而设的. 当链表为空的时候,带头结点的头指针就指向头结点,头结点的指针域存储的数值为NULL. &l ...

  2. 数据结构学习(二)——单链表的操作之头插法和尾插法创建链表

    http://blog.csdn.net/abclixu123/article/details/8210109 链表也是线性表的一种,与顺序表不同的是,它在内存中不是连续存放的.在C语言中,链表是通过 ...

  3. 单链表的头插法和尾插法c语言实现

    /*单链表的头插法和尾插法c语言实现*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #d ...

  4. 采用头插法和尾插法建立单链表

    面说一下如果用C语言建立单链表,分为头插法和尾插法两种. 采用头插法建立单链表 该方法从一个空表开始,生成新结点,并将读取到的数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头,即头结点之后 ...

  5. 头插法和尾插法建立带头节点的单链表

    有两种方法建立单链表,尾插法和头插法,他们的区别是:头插法是按照输入元素倒序建立,为尾插法为顺序插入,并且多一个尾节点,我们一般使用尾插法. 一.头插法 代码为: pCurr -> next = ...

  6. c语言 链表建立头插法尾插法,单链表的创建(头插法和尾插法)

    单链表的创建分为头插法和尾插法,头插法是不断地向头结点插入新的结点.这样会使你所插入的结点值呈现逆序,所以头插法也可以实现单链表的逆置.尾插法是不断地向插入的新元素之后再插入新的元素.需要注意的是头插 ...

  7. 不带头结点的单链表的创建(头插法和尾插法)

    1.用头插法建立不带头结点的单链表 #include<iostream> using namespace std;//单链表的结构体 typedef struct Node {int da ...

  8. 头插法和尾插法创建链表(有无头结点)

    头插法和尾插法创建链表(有无头结点) 文章目录 头插法和尾插法创建链表(有无头结点) 1 头插法 1.1头插法建表规则: 1.2 头插法建表代码实现 2 尾插法 2.1 尾插法建表规则: 2.2 尾插 ...

  9. C语言的双向链表头插法和尾插法,指定节点删除

    文章目录 前言 头插法 尾插法 删除节点 测试代码如下 前言 双向链表和单链表的唯一区别就是多个一个指针域而已,该指针域可以访问链表的上一个节点. 关于构造双向链表的过程我们常见的有两种方法,和单链表 ...

  10. 头插法和尾插法的详细区别

    浅析线性表(链表)的头插法和尾插法的区别及优缺点 线性表作为数据结构中比较重要的一种,具有操作效率高.内存利用率高.结构简单.使用方便等特点,今天我们一起交流一下单向线性表的头插法和尾插法的区别及优缺 ...

最新文章

  1. js在客户端创建文件——ActiveXObject
  2. 如何获得tomcat管理员账号
  3. H3C MSTP实验
  4. sql聚集索引和非聚集索引_SQL Server中非聚集索引概述
  5. 专家系统代码实现_前端代码是怎样智能生成的 - 语义化篇
  6. 杭州有那些APP外包公司?
  7. MaxEnt: 最大熵模型(Maximum Entropy Models)(一)
  8. CentOS快速安装、配置Web服务器(Apache)
  9. uniapp实现复制功能
  10. Xcode及Mac快捷键
  11. shell wait的用法及使用“和wait”并行运行
  12. [问题]mpu9250+bmp280数据读取
  13. http请求HttpServletRequest详解
  14. 两位图灵奖得主万字长文:新计算机架构,黄金十年爆发!
  15. 题解报告:P1577 切绳子(二分答案)
  16. 毛球科技观察院|基于区块链技术重新构想电力市场
  17. win系列服务器,windows服务器系列系统
  18. 达梦数据库实时主备集群的同步机制和切换机制
  19. 站群目前来说依然在站长圈非常的流行
  20. 二进制好看的深浅色系颜色大全

热门文章

  1. 【数据挖掘】2022年深信服科技机器学习工程师笔试
  2. iOS 实现时间线列表效果
  3. 【分享】豆瓣上排名top100的书籍
  4. 弱小目标检测领域下图像的信噪比(SNR)计算方法
  5. 【机器学习】实验5布置:基于K-近邻的车牌号识别
  6. 微信小程序 java网上购物商城系统
  7. 软件安全(彭国军)期末复习
  8. 高斯滤波 c++实现
  9. OTL音频功率放大器
  10. 程序员修炼之道——通向务实的最高境界(第二版)