数据结构——Java实现单链表
一、分析
单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点由元素和指针构成。在Java中,我们可以将单链表定义成一个类,单链表的基本操作即是类的方法,而结点就是一个个实例化的对象,每个对象中都有“元素值”和“下一结点地址”两个属性。在“下一结点地址”属性中存储的是下一个对象的引用,这样,一个个对象连在一起就成为了单链表。
单链表有以下基本操作:
1、初始化单链表
2、销毁单链表
3、清空单链表
4、检测单链表是否为空
5、返回单链表的元素个数
6、返回单链表中指定位置元素的值
7、返回单链表中第一个与指定值相同的元素的位置
8、返回指定元素的直接前驱
9、返回指定元素的直接后继
10、向指定位置插入元素
11、删除指定位置的元素
12、遍历单链表
为了方便对单链表进行操作,我们还需要引入一个头结点,头结点中不存储元素值,只存储单链表第一个结点的地址。初始化单链表即创建头结点,而销毁单链表即销毁头结点。
二、实现
1、定义类属性和构造函数
class InitList{ private int [] data = new int[1]; //用来存储元素值,之所以用数组而不用整型,是为了用null来表示头结点 private InitList nextList; //下一结点地址 public InitList() { //创建头结点的构造函数
this.data = null;
this.nextList = null;
} public InitList(int data) { //创建普通结点的构造函数
this.data[0] = data;
this.nextList = null;
}
}
2、清空单链表
public void clearList() {
this.nextList = null; //将头结点的下一结点地址(即单链表的第一个结点的地址)置空,则单链表会因缺少引用而被jvm回收,实现清空
}
3、检测单链表是否为空
public boolean listEmpty() {
if(this.nextList == null) { //通过判断头结点的下一结点地址是否为空,即可判断单链表是否为空
return true;
}
return false;
}
4、返回单链表的元素个数
public int listLength() { InitList theList = this.nextList; //获取头结点的下一结点地址
int i = 0; //计数器初始化 for (i = 0; theList != null; i++) { //循环判断结点地址是否为空,如果不为空,则表明存在结点,计数器i加一;如果为空,则表明已到达单链表尾部,退出循环
theList = theList.nextList; //取下一结点进行判断
}
return i; //返回计数器的值
}
5、返回单链表中指定位置元素的值
public int [] getElem(int site) { if(site < 1) { //判断输入的位置是否合法
return null;
} InitList theList = this; //得到头结点的地址 for (int i = 0; i < site; i++) { //循环读取结点,直到指定的位置
theList = theList.nextList; //获取下一结点的地址
if(theList == null) { //如果下一结点地址为空,则表明已经到达单链表末尾,指定的位置超出了单链表的长度
return null; //未取到元素,返回null
}
}
return theList.data; //返回指定位置元素值
}
6、返回单链表中第一个与指定值相同的元素的位置
public int locateElem(int value) { InitList theList = this.nextList; for(int i = 1; theList != null; i++) { //如果取得的结点不为空,执行循环
if(theList.data[0] == value) { //比较结点值与给定的值是否相等
return i; //相等返回结点位置
}
theList = theList.nextList; //取下一结点地址
} return 0; //未找到则返回零
}
7、返回指定元素的直接前驱
public int [] priorElem(int value) { InitList theList = this.nextList; if(theList == null) { //如果头结点的下一结点为空,则表明单链表为空,返回null
return null;
} InitList theNextList = this.nextList.nextList; //获取单链表的第二个结点
int [] ret = new int[this.listLength()]; //创建一个与单链表长度相同的数组,用来存储找到的直接前驱的值
int i = 1; //计数器 while (theNextList != null) { //因为单链表的第一个结点没有直接前驱,因此从第二个结点开始循环
if(theNextList.data[0] == value) { //如果与给定值相等,则取得其前驱,计数器加一
ret[i] = theList.data[0];
i++;
}
theList = theNextList; //取下一地址,准备下一循环
theNextList = theNextList.nextList;
} if(i == 1) { //i为1表明未取到直接前驱
return null;
} ret[0] = i - 1; //将计数器的值存入数组第0位
return ret;
}
8、返回指定元素的直接后继
public int [] nextElem(int value) { //与获取直接前驱类似,这里不再赘述 InitList theList = this.nextList; if(theList == null) {
return null;
} InitList theNextList = this.nextList.nextList;
int [] ret = new int[this.listLength()];
int i = 1; while (theNextList != null) {
if(theList.data[0] == value) {
ret[i] = theNextList.data[0];
i++;
}
theList = theNextList;
theNextList = theNextList.nextList;
} if(i == 1) {
return null;
} ret[0] = i - 1;
return ret;
}
9、向指定位置插入元素
public boolean listInsert(int site,int value) { if(site < 1) { //判断指定位置是否合法
return false;
}
6
7 InitList list = new InitList(value);
InitList theNextList = this;
InitList theList = null; for(int i = 0; i < site; i++) { //循环读取到指定位置
theList = theNextList;
if(theList == null) { //如果为空,表示已到单链表末尾,返回false
return false;
}
theNextList = theNextList.nextList;
} list.nextList = theNextList; //将新结点插入指定位置中
theList.nextList = list;
return true;
}
10、删除指定位置的元素
public boolean listDelete(int site) { InitList theList = this;
InitList theNextList = this.nextList; if(site < 1 || theNextList == null) { //判断指定位置是否合法和单链表是否为空
return false;
}else if(site == 1) { //如果要删除的是第一个结点,则直接删除
theList.nextList = theNextList.nextList;
return true;
} for(int i = 1; i < site; i++) { //循环读取到指定位置
theNextList = theNextList.nextList;
if(theNextList == null) {
return false;
}
theList = theList.nextList;
} theList.nextList = theNextList.nextList; //删除指定位置的结点
return true;
}
11、遍历单链表
public String traverseList() { //这里通过输出单链表来表示遍历 InitList theList = this.nextList;
String s = ""; //用来存储单链表的值 while(theList != null) { //循环获取结点值
s += theList.data[0] + "、";
theList = theList.nextList;
} if(s.length() == 0) { //如未获取到值,直接返回s
return s;
} return s.substring(0,s.length() - 1); //去除最后的顿号后返回
}
三、小结
以上就是单链表用Java的实现,由于只定义了整数的数组,因此只能操作整数数据,但单链表的基本思想都已实现。
四、纠正
隔了一段时间又回来看代码,猛地发现这段代码其实还不够完善。(⊙x⊙;)
将单链表的基本操作定义成了InitList类的方法,实例化结点时,会使每个结点都拥有这些方法,然而其实只有头结点需要这些方法,其他结点都不需要。
因此可以将InitList类定义成头节点类,而其他节点定义成头节点的内部类,这样,就只有头节点可以操作其他节点。
由于要修改的地方太多,这里我就不修改了,放在这里提醒自己。(就是因为懒……(><))
数据结构——Java实现单链表的更多相关文章
- Java实现单链表的各种操作
Java实现单链表的各种操作 主要内容:1.单链表的基本操作 2.删除重复数据 3.找到倒数第k个元素 4.实现链表的反转 5.从尾到头输出链表 6.找到中间节点 7.检测链表是否有环 8.在 ...
- java实现单链表的增删功能
JAVA 实现单链表的增删功能 package linked; class LinkedTable{ } public class LinkedTableTest { public static vo ...
- 使用java实现单链表(转载自:https://www.cnblogs.com/zhongyimeng/p/9945332.html)
使用java实现单链表----(java中的引用就是指针)转载自:https://www.cnblogs.com/zhongyimeng/p/9945332.html ? 1 2 3 4 5 6 7 ...
- java实现单链表、栈、队列三种数据结构
一.单链表 1.在我们数据结构中,单链表非常重要.它里面的数据元素是以结点为单位,每个结点是由数据元素的数据和下一个结点的地址组成,在java集合框架里面 LinkedList.HashMap(数组加 ...
- java实现单链表常见操作
一.概述: 本文主要总结单链表常见操作的实现,包括链表结点添加.删除:链表正向遍历和反向遍历.链表排序.判断链表是否有环.是否相交.获取某一结点等. 二.概念: 链表: 一种重要的数据结构,HashM ...
- js数据结构与算法--单链表的实现与应用思考
链表是动态的数据结构,它的每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称指针或链接)组成. 现实中,有一些链表的例子. 第一个就是寻宝的游戏.你有一条线索,这条线索是指向寻找下一条线 ...
- Java实现单链表反转操作
单链表是一种常见的数据结构,由一个个节点通过指针方式连接而成,每个节点由两部分组成:一是数据域,用于存储节点数据.二是指针域,用于存储下一个节点的地址.在Java中定义如下: public class ...
- 用Java实现单链表的基本操作
笔试题中经常遇到单链表的考题,下面用java总结一下单链表的基本操作,包括添加删除节点,以及链表转置. package mars; //单链表添加,删除节点 public class ListNode ...
- Java实现单链表的快速排序和归并排序
本文描述了LeetCode 148题 sort-list 的解法. 题目描述如下: Sort a linked list in O(n log n) time using constant space ...
随机推荐
- 开源方案搭建可离线的精美矢量切片地图服务-3.Mapbox个性化地图定制入门
1.简介 mapbox是一家非常牛的公司,比如像特斯拉.DJI大疆创新.孤独星球.Airbnb.GitHub.Cisco.Snap.飞猪.Keep.Bosch这些在国内外各自领域中响当当的企业都是它的 ...
- Unix中的I/O模型
本文所指的I/O均是网络I/O. 一. POSIX对同步.异步I/O的定义 我们先大致看看POSIX对同步.异步的定义,不用细究,重点看我标红的部分就行. 同步I/O会导致请求进程阻塞,直到I/O操作 ...
- OsharpNS轻量级.net core快速开发框架简明入门教程-基于Osharp实现自己的业务功能
OsharpNS轻量级.net core快速开发框架简明入门教程 教程目录 从零开始启动Osharp 1.1. 使用OsharpNS项目模板创建项目 1.2. 配置数据库连接串并启动项目 1.3. O ...
- Scala 编码习惯
1. 不用var.var是可以被不断修改的,而val是不能被修改的.使用val而不是var能让你的程序更强壮,bug更少,更好调试,更容易测试,在并发条件下,更容易调优而获得更好的性能.数学证明我们不 ...
- c# 基于文件系统实现的队列处理类
现实业务中经常遇到需要队列处理的问题. 问题场景: 客户端记录设备运行数据,传输给服务器.在传输中可能存在延迟或中断情况.当中断时,系统传输数据可能因为无法传输或电脑重启,会导致服务器数据记录不连续. ...
- Brown Mood Median Test
Brown-Mood Median Test 对于两独立样本尺度中的位置参数(中位数)检验问题: \(H_0: med_x = med_y\) \(H_1=med_x > med_y\) 在 ...
- 『简单dp测试题解』
这一次组织了一场\(dp\)的专项考试,出了好几道经典的简单\(dp\)套路题,特开一篇博客写一下题解. Tower(双向dp) Description 信大家都写过数字三角形问题,题目很简单求最大化 ...
- 介绍几款 Python 类型检查工具
近日,微软在 Github 上开源了一个 Python 静态类型检查工具:pyright ,引起了社区内的多方关注. 微软在开源项目上的参与力度是越来越大了,不说收购 Github 这种大的战略野心, ...
- HTML阻止iframe跳转页面并使用iframe在页面内嵌微信网页版
昨天看到这篇文章[置顶]开源组件NanUI一周年 - 使用HTML/CSS/JS来构建.Net Winform应用程序界面 就想弄一个winform结合html5的一个小东西,突有兴致,想在里面嵌套一 ...
- Android App渗透测试工具drozer,Qark,Androguard
一. drozer简介 drozer(以前称为Mercury)是一款Android安全测试框架. drozer允许您通过承担应用程序的角色并与Dalvik VM,其他应用程序的IPC端点和底层操作系统 ...