一、单链表基本概念

单链表是一种链式存取的数据结构,用一组地址任意的存储单元(一般是非连续存储单元)存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素data + 指针next(指示后继元素存储位置)。其存储结构如图:

二、JAVA实现单链表

数据结构:

单链表有一个属性head和一些重要的方法,head为链表结点Node类的实例。Node类中包含成员变量:data,next。data为当前节点的数据域,next为指针域,指向下一个结点。

1、结点

  1. class Node{
  2. int data;
  3. Node next=null;
  4. public Node(int data){
  5. this.data=data;
  6. }
  7. public Node(){}
  8. public void display() {
  9. System. out.print(this.data + " "); //结点打印函数
  10. }
  11. }

2、单链表

  1. public class linkList {
  2. Node head=new Node();
  3. //各种方法的实现代码
  4. }

函数

1、链表添加元素之头插

每次来了新元素将其插入到头结点之后

  1. public void insertHead(int val){
  2. Node newnode=new Node(val);
  3. if(head.next!=null){
  4. newnode.next=head.next;
  5. }
  6. head.next=newnode;
  7. }

2、链表添加元素之尾插

每次来了新元素将其插入到链表最后位置

  1. public void insertTail(int val){
  2. Node newnode=new Node(val);
  3. Node walkPointer=head;
  4. while(walkPointer.next!=null){
  5. walkPointer=walkPointer.next;
  6. }
  7. walkPointer.next=newnode;
  8. }

3、任意位置插入

  1. public void insert(int pos,int val){
  2. int index=0;
  3. if(pos>=0&&pos<=this.getLength()){
  4. Node walkPointer=head;
  5. while(index!=pos){
  6. walkPointer=walkPointer.next;
  7. index++;
  8. }
  9. Node newnode=new Node(val);
  10. newnode.next=walkPointer.next;
  11. walkPointer.next=newnode;
  12. }
  13. }

4、获取链表长度

  1. public int getLength(){
  2. int length=0;
  3. Node walkPointer=head;
  4. while(walkPointer.next!=null){
  5. walkPointer=walkPointer.next;
  6. length++;
  7. }
  8. return length;
  9. }

5、删除指定结点(头指针未知):实质用该结点代替其next结点

  1. public boolean delete(Node delnode){
  2. if(delnode==null||delnode.next==null){
  3. return false;
  4. }
  5. delnode=delnode.next;
  6. return true;
  7. }

6、遍历链表

  1. public void print() {
  2. Node walkPointer=head;
  3. System.out.println("**链表结点遍历**");
  4. while(walkPointer.next!=null){
  5. walkPointer=walkPointer.next;
  6. System.out.print(walkPointer.data + " ");
  7. }
  8. System.out.println();
  9. }

7、链表逆置

之前遇到一道题目,需要将链表元素从尾到头创建ArrayList数组的题目,这里相同的思路,只不过是逆序输出创建新的链表。

两者不同之处在于:对于非递归的方式,链表逆序输出创建新数组时,采用头插的方式相对费时,需要将第一个元素之后的元素后移;而链表逆序输出创建新链表时,采用头插的方式相对快速,只要找到头结点即可一步插入。相反的,对于递归的方式,链表逆序输出创建新数组时,采用尾插的方式相比创建新链表要省时。

思路1:(递归)将链表结点的数据顺序取出存储在栈中——从栈中pop元素采用尾插的方式建立新链表(链表的尾插比较费时,需要遍历到链表最后一个元素才能插入元素)

  1. public linkList reverse1(){
  2. linkList list=new linkList();
  3. Stack<Integer> stack=new Stack<Integer>();
  4. Node walkPointer=head.next;
  5. while(walkPointer!=null){
  6. stack.push(walkPointer.data);
  7. walkPointer=walkPointer.next;
  8. }
  9. while(!stack.empty()){
  10. list.insertTail(stack.pop());
  11. }
  12. return list;
  13. }

思路2:(非递归)声明新链表,将原链表元素顺序取出,同时采用头插的方式插入到新链表中(链表的头插相对于尾插耗时更小)

  1. public linkList reverse(){
  2. linkList list=new linkList();
  3. Node walkPointer=head.next;
  4. Node temp=new Node();
  5. while(walkPointer!=null){
  6. list.insertHead(walkPointer.data);
  7. walkPointer=walkPointer.next;
  8. }
  9. return list;
  10. }

整体代码(含测试)

  1. package struct;
  2.  
  3. import java.util.Stack;
  4.  
  5. class Node{
  6. int data;
  7. Node next=null;
  8. public Node(int data){
  9. this.data=data;
  10. }
  11. public Node(){}
  12. public void display() {
  13. System. out.print(this.data + " "); //结点打印函数
  14. }
  15. }
  16. public class linkList {
  17. Node head=new Node();
  18. //头插
  19. public void insertHead(int val){
  20. Node newnode=new Node(val);
  21. if(head.next!=null){
  22. newnode.next=head.next;
  23. }
  24. head.next=newnode;
  25. }
  26.  
  27. //尾插
  28. public void insertTail(int val){
  29. Node newnode=new Node(val);
  30. Node walkPointer=head;
  31. while(walkPointer.next!=null){
  32. walkPointer=walkPointer.next;
  33. }
  34. walkPointer.next=newnode;
  35. }
  36.  
  37. //获得链表长度
  38. public int getLength(){
  39. int length=0;
  40. Node walkPointer=head;
  41. while(walkPointer.next!=null){
  42. walkPointer=walkPointer.next;
  43. length++;
  44. }
  45. return length;
  46. }
  47.  
  48. //任意位置插入
  49. public void insert(int pos,int val){
  50. int index=0;
  51. if(pos>=0&&pos<=this.getLength()){
  52. Node walkPointer=head;
  53. while(index!=pos){
  54. walkPointer=walkPointer.next;
  55. index++;
  56. }
  57. Node newnode=new Node(val);
  58. newnode.next=walkPointer.next;
  59. walkPointer.next=newnode;
  60. }
  61. }
  62.  
  63. //链表的逆置(非递归,同从尾到头构建列表,链表的头插复杂度比列表头插低很多)
  64. public linkList reverse(){
  65. linkList list=new linkList();
  66. Node walkPointer=head.next;
  67. Node temp=new Node();
  68. while(walkPointer!=null){
  69. list.insertHead(walkPointer.data);
  70. walkPointer=walkPointer.next;
  71. }
  72. return list;
  73. //笨方法
  74. // Node preNode=head;
  75. // Node walkPointer=head.next;
  76. // head.next=null;
  77. // Node nextNode=new Node();
  78. // while(walkPointer!=null){
  79. // nextNode=walkPointer.next;
  80. // walkPointer.next=preNode;
  81. // preNode=walkPointer;
  82. // walkPointer=nextNode;
  83. // }
  84. // list.head.next=preNode;
  85. // return list;
  86. }
  87.  
  88. //链表的逆置(递归,使用栈。类似于从尾到头输出列表)
  89. public linkList reverse1(){
  90. linkList list=new linkList();
  91. Stack<Integer> stack=new Stack<Integer>();
  92. Node walkPointer=head.next;
  93. while(walkPointer!=null){
  94. stack.push(walkPointer.data);
  95. walkPointer=walkPointer.next;
  96. }
  97. while(!stack.empty()){
  98. list.insertTail(stack.pop());
  99. }
  100. return list;
  101. }
  102.  
  103. //删除指定结点(头指针未知),实质用该结点代替其next结点
  104. public boolean delete(Node delnode){
  105. if(delnode==null||delnode.next==null){
  106. return false;
  107. }
  108. delnode=delnode.next;
  109. return true;
  110. }
  111.  
  112. //打印遍历
  113. public void print() {
  114. Node walkPointer=head;
  115. System.out.println("**链表结点遍历**");
  116. while(walkPointer.next!=null){
  117. walkPointer=walkPointer.next;
  118. System.out.print(walkPointer.data + " ");
  119. }
  120. System.out.println();
  121. }
  122. @SuppressWarnings("null")
  123. public static void main(String []args){
  124. linkList list=new linkList();
  125. list.insertHead(12);
  126. list.insertHead(15);
  127. list.insertHead(2);
  128. list.insertHead(3);
  129. list.insert(0,4);
  130. list.print();
  131. System.out.println("链表长度");
  132. System.out.println(list.getLength());
  133. System.out.println("!!链表转置后的头结点数据!!");
  134. linkList returnlist=new linkList();
  135. returnlist=list.reverse();
  136. returnlist.print();
  137. returnlist=list.reverse1();
  138. returnlist.print();
  139. }
  140. }

数据结构之单链表的实现-java的更多相关文章

  1. 数据结构(一) 单链表的实现-JAVA

    数据结构还是很重要的,就算不是那种很牛逼的,但起码得知道基础的东西,这一系列就算是复习一下以前学过的数据结构和填补自己在这一块的知识的空缺.加油.珍惜校园中自由学习的时光.按照链表.栈.队列.排序.数 ...

  2. 数据结构(2):单链表学习使用java实现

    单链表是单向链表,它指向一个位置: 单链表常用使用场景:根据序号排序,然后存储起来. 代码Demo: package com.Exercise.DataStructure_Algorithm.Sing ...

  3. 数据结构之单链表(基于Java实现)

    链表:在计算机中用一组任意的存储单元存储线性表的数据元素称为链式存储结构,这组存储结构可以是连续的,也可以是不连续的,因此在存储数据元素时可以动态分配内存. 注:在java中没有指针的概念,可以理解为 ...

  4. Python数据结构之单链表

    Python数据结构之单链表 单链表有后继结点,无前继结点. 以下实现: 创建单链表 打印单链表 获取单链表的长度 判断单链表是否为空 在单链表后插入数据 获取单链表指定位置的数据 获取单链表指定元素 ...

  5. 理解单链表的反转(java实现)

    要求很简单,输入一个链表,反转链表后,输出新链表的表头.   反转链表是有2种方法(递归法,遍历法)实现的,面试官最爱考察的算法无非是斐波那契数列和单链表反转,递归方法实现链表反转比较优雅,但是对于不 ...

  6. javascript数据结构之单链表

    下面是用javascript实现的单链表,但是在输出的时候insert方法中存在问题,chrome的console报错说不能读取空的属性,调试了很久都没有通过,先在这里存着,以后再来修改一下. //数 ...

  7. Java数据结构之单链表

    这篇文章主要讲解了通过java实现单链表的操作,一般我们开始学习链表的时候,都是使用C语言,C语言中我们可以通过结构体来定义节点,但是在Java中,我们没有结构体,我们使用的是通过类来定义我们所需要的 ...

  8. Java数据结构-03单链表(二)

    在之前我们封装了一些操作在接口类中,并在抽象类实现了相同的方法.下面我们开始写代码: 无头结点单链表:(注意下面的AbstractList是之前抽取的类,不是java.util包下的类) public ...

  9. 图解Java数据结构之单链表

    本篇文章介绍数据结构中的单链表. 链表(Linked List)介绍 链表可分为三类: 单链表 双向链表 循环列表 下面具体分析三个链表的应用. 单链表 链表是有序的列表,它在内存中存储方式如下: 虽 ...

随机推荐

  1. docker之CPU配额参数的混合使用

    在启动容器的时候有很多参数,这里来实践一下与CPU相关的参数. 实例: 创建两个容器,docker10.docker20,让两个容器只运行在CPU0上,然后测试CPU使用率. [root@openst ...

  2. 回调函数(callback) python / c++ 演示

    什么是回调函数? 我们绕点远路来回答这个问题. 编程分为两类:系统编程(system programming)和应用编程(application programming).所谓系统编程,简单来说,就是 ...

  3. css垂直居中布局总结

    简介 总结记录一下经常需要用到垂直居中布局,欢迎补充(空手套...O(∩_∩)O) 以下栗子如果未特别标注同一使用这样的html结构 <div class="container&quo ...

  4. JVM 监控工具——jps

    [参考文章]:[Linux运维入门]Jstatd方式远程监控Linux下 JVM运行情况 1. jps简介 显示系统内所有的HotSpot虚拟机进程. 且只能查看当前用户下的Java进程信息: 2. ...

  5. Anaconda官网下载太慢/出错,以及Anaconda下载包又慢又出错的总体方法,应该如何快速下载,使用上海科技大学的开源镜像站即可

    1.最新更新:清华源和中科大源都已经挂了,不要再用他们的镜像源了!!!用上海科技大学的镜像!!!! 2.其次,CSDN上大多的快速装包法都在现在(2019.5.11)出现了问题,也不全,本文是亲自实践 ...

  6. WPF使用cefsharp 下载地址

    源码下载: https://github.com/cefsharp/CefSharp dll类库包下载nuget: https://www.nuget.org/packages/CefSharp.Wp ...

  7. Python标准组件ConfigParser配置文件解析器,保存配置时支持大写字母的方法

    虽然自己已经改用xml作为配置文件首选格式了,但是有时候还是需要解析ini.cfg文件(为了兼容早期版本或者其他作者的软件). 基本上Python自带的ConfigParser足够应对了,但是美中不足 ...

  8. java最常见的5个错误

    1. Null 的过度使用 避免过度使用 null 值是一个最佳实践.例如,更好的做法是让方法返回空的 array 或者 collection 而不是 null 值,因为这样可以防止程序抛出 Null ...

  9. gitlab仓库的使用

    一.gitlab简介 gitlab是一个用于仓库管理系统的开源项目,使用git作为代码管理工具,并在此基础上搭建web服务. [管理命令] gitlab-ctl stop        gitlab- ...

  10. vue-router懒加载

    require.ensure(dependencies:String [],callback:function(require),errorCallback:function(error),chunk ...