线性表的Java实现--链式存储(单向链表)
单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始。
链式存储结构的线性表将采用一组任意的存储单元存放线性表中的数据元素。由于不需要按顺序存储,链表在插入、删除数据元素时比顺序存储要快,但是在查找一个节点时则要比顺序存储要慢
使用链式存储可以克服顺序线性表需要预先知道数据大小的缺点,链表结构可以充分利用内存空间,实现灵活的内存动态管理。但是链式存储失去了数组随机存取的特点,同时增加了节点的指针域,空间开销较大。
下图就是最简单最一般的单向链表:

新增节点:
将值为element的新节点插入到第index的位置上。
首先要先找到索引为index-1的节点,然后生成一个数据为element的新节点newNode,并令index-1处节点的next指向新节点,新节点的next指向原来index处的节点。
删除节点:
删除第index个节点,第index节点是由index-1出的节点引用的,因此删除index的节点要先获取index-1处的节点,然后让index-1出节点的next引用到原index+1处的节点,并释放index处节点即可。

单向链表的Java实现
下面的程序分别实现了线性表的初始化、获取线性表长度、获取指定索引处元素、根据值查找、插入、删除、清空等操作。
package com.liuhao.algorithm;
public class LinkList<T> {
// 定义一个内部类Node,代表链表的节点
private class Node {
private T data;// 保存数据
private Node next;// 指向下个节点的引用
// 无参构造器
public Node() {
}
// 初始化全部属性的构造器
public Node(T data, Node next) {
this.data = data;
this.next = next;
}
}
private Node header;// 保存头结点
private Node tail;// 保存尾节点
private int size;// 保存已含有的节点数
// 创建空链表
public LinkList() {
header = null;
tail = null;
}
// 已指定数据元素创建链表,只有一个元素
public LinkList(T element) {
header = new Node(element, null);
// 只有一个节点,header,tail都指向该节点
tail = header;
size++;
}
// 返回链表的长度
public int length() {
return size;
}
// 获取指定索引处的元素
public T get(int index) {
return this.getNodeByIndex(index).data;
}
//获取指定位置的节点
private Node getNodeByIndex(int index){
if(index < 0 || index > size-1){
throw new IndexOutOfBoundsException("索引超出线性表范围");
}
Node current = header;//从header开始遍历
for(int i=0; i<size && current!=null; i++,current=current.next){
if(i == index){
return current;
}
}
return null;
}
//按值查找所在位置
public int locate(T element){
Node current = header;
for(int i=0; i<size && current!=null; i++, current=current.next){
if(current.data.equals(element)){
return i;
}
}
return -1;
}
//指定位置插入元素
public void insert(T element, int index){
if(index < 0 || index > size){
throw new IndexOutOfBoundsException("索引超出线性表范围");
}
//如果是空链表
if(header == null){
add(element);
}
else{
//当index为0时,即在链表头处插入
if(0 == index){
addAtHead(element);
}
else{
Node prev = getNodeByIndex(index - 1);//获取前一个节点
//让prev的next指向新节点,新节点的next指向原来prev的下一个节点
prev.next = new Node(element, prev.next);
size++;
}
}
}
//在尾部插入元素
public void add(T element) {
//如果链表是空的
if(header == null){
header = new Node(element, null);
//只有一个节点,headwe,tail都该指向该节点
tail = header;
}
else{
Node newNode = new Node(element, null);//创建新节点
tail.next = newNode;//尾节点的next指向新节点
tail = newNode;//将新节点作为尾节点
}
size++;
}
//头部插入
public void addAtHead(T element){
//创建新节点,让新节点的next指向header
//并以新节点作为新的header
Node newNode = new Node(element, null);
newNode.next = header;
header = newNode;
//若插入前是空表
if(tail == null){
tail = header;
}
size++;
}
//删除指定索引处的元素
public T delete(int index){
if(index < 0 || index > size-1){
throw new IndexOutOfBoundsException("索引超出线性表范围");
}
Node del = null;
//若要删除的是头节点
if(index == 0){
del = header;
header = header.next;
}
else{
Node prev = getNodeByIndex(index - 1);//获取待删除节点的前一个节点
del = prev.next;//获取待删除节点
prev.next = del.next;
del.next = null;//将被删除节点的next引用置为空
}
size--;
return del.data;
}
//删除最后一个元素
public T remove(){
return delete(size - 1);
}
//判断线性表是否为空
public boolean isEmpty(){
return size == 0;
}
//清空线性表
public void clear(){
//将header,tail置为null
header = null;
tail = null;
size = 0;
}
public String toString(){
if(isEmpty()){
return "[]";
}
else{
StringBuilder sb = new StringBuilder("[");
for(Node current = header; current != null; current = current.next){
sb.append(current.data.toString() + ", ");
}
int len = sb.length();
return sb.delete(len-2, len).append("]").toString();
}
}
}
测试代码
package com.liuhao.test;
import org.junit.Test;
import com.liuhao.algorithm.LinkList;
public class LinkListTest {
@Test
public void test() {
// 测试构造函数
LinkList<String> list = new LinkList("好");
System.out.println(list);
// 测试添加元素
list.add("ni");
list.add("没");
System.out.println(list);
// 在头部添加
list.addAtHead("五月");
System.out.println(list);
// 在指定位置添加
list.insert("摩卡", 2);
System.out.println(list);
// 获取指定位置处的元素
System.out.println("第2个元素是(从0开始计数):" + list.get(2));
// 返回元素索引
System.out.println("摩卡在的位置是:" + list.locate("摩卡"));
System.out.println("moka所在的位置:" + list.locate("moka"));
// 获取长度
System.out.println("当前线性表的长度:" + list.length());
// 判断是否为空
System.out.println(list.isEmpty());
// 删除最后一个元素
list.remove();
System.out.println("调用remove()后:" + list);
// 获取长度
System.out.println("当前线性表的长度:" + list.length());
// 删除指定位置处元素
list.delete(3);
System.out.println("删除第4个元素后:" + list);
// 获取长度
System.out.println("当前线性表的长度:" + list.length());
// 清空
list.clear();
System.out.println(list);
// 判断是否为空
System.out.println(list.isEmpty());
}
}
线性表的Java实现--链式存储(单向链表)的更多相关文章
- 线性表的Java实现--链式存储(双向链表)
有了单向链表的基础,双向链表的实现就容易多了. 双向链表的一般情况: 增加节点: 删除节点: 双向链表的Java实现: package com.liuhao.algorithm; publi ...
- 数据结构导论 四 线性表的顺序存储VS链式存储
前几章已经介绍到了顺序存储.链式存储 顺序存储:初始化.插入.删除.定位 链式存储:初始化.插入.删除.定位 顺序存储:初始化 strudt student{ int ID://ID char nam ...
- 算法与数据结构(一) 线性表的顺序存储与链式存储(Swift版)
温故而知新,在接下来的几篇博客中,将会系统的对数据结构的相关内容进行回顾并总结.数据结构乃编程的基础呢,还是要不时拿出来翻一翻回顾一下.当然数据结构相关博客中我们以Swift语言来实现.因为Swift ...
- 线性表的顺序存储和链式存储的实现(C)
//线性表的顺序存储 #include <stdio.h>typedef int DataType;#define MaxSize 15//定义顺序表typedef struct { Da ...
- c数据结构 -- 线性表之 复杂的链式存储结构
复杂的链式存储结构 循环链表 定义:是一种头尾相接的链表(即表中最后一个结点的指针域指向头结点,整个链表形成一个环) 优点:从表中任一节点出发均可找到表中其他结点 注意:涉及遍历操作时,终止条件是判断 ...
- 线性表的顺序存储和链式存储c语言实现
一.线性表的顺序存储 typedef int ElemType;typedef struct List { ElemType *data;//动态分配 ,需要申请空间 int length; }Lis ...
- Java实现链式存储的二叉查找树(递归方法)
二叉查找树的定义: 二叉查找树或者是一颗空树,或者是一颗具有以下特性的非空二叉树: 1. 若左子树非空,则左子树上所有节点关键字值均小于根节点的关键字: 2. 若右子树非空,则右子树上所有节点关键字值 ...
- Java实现链式存储的二叉树
二叉树的定义: 二叉树(BinaryTree)是n(n≥0)个结点的有限集,它或者是空集(n=0),或者由一个根结点及两棵互不相交的.分别称作这个根的左子树和右子树的二叉树组成. 二叉树的遍历方式主要 ...
- Java实现线性表-顺序表示和链式表示
顺序表示和链式表示的比较: 1.读写方式:顺序表可以顺序存取,也可以随机存取:链表只能从表头顺序存取元素: 2.逻辑结构与物理结构:顺序存储时,逻辑上相邻的元素其对应的物理存储位置也相邻:链式存储时, ...
随机推荐
- 【算法笔记】B1053 住房空置率
看了半天发现是题目理解错了,可能空置的里面观察期超过D则判定空置,而不是用电量低于e的天数超过D. code #include <bits/stdc++.h> using namespac ...
- 'qt_sql_default_connection' is still in use
出现这个告警是因为打开了多个db而没有及时关闭,网上搜了答案是使用完了执行 QSqlDatabase::removeDatabase(m_connectionName); 泄漏的问题有所改善,但点快了 ...
- 有道词典命令行查询工具(Mac/Ubuntu)
说明:此工具是基于node.js的,所以必须安装npm. 官网:https://github.com/kenshinji/yddict 安装: Mac: # 安装npm brew install np ...
- [Xamarin] 透過 IsolatedStorageFile儲存資料(转帖)
開發手機App通常都會遇到想要儲存資料的,舉個例來說,像是 (圖片來源:http://docs.xamarin.com/guides/android/application_fundamentals/ ...
- (转)架构师之DNS实战CentOS7VSCentOS6
原文:https://www.abcdocker.com/abcdocker/1298 CentOS7上使用bind9搭建DNS主从服务器-----http://blog.51cto.com/yich ...
- io流之节点流inputstream、outputstream、reader、writer
例子程序:读取工作空间下 package io; import java.io.*; public class TestFileInputStream { public static void mai ...
- 安装win7 64位和win10 64位双系统小结
1.gpt比mbr更先进.与主启动记录 (MBR) 分区方法相比,GPT 具有更多的优点,因为它允许每个磁盘有多达 128 个分区(mbr只支持4个分区),支持高达 18 千兆兆字节的卷大小,允许将主 ...
- 数据库其他注入思路 - 万能密码 - cookie注入 -搜索型注入
另类登录注入形式: 经常有一类验证(ASP,PHP,JSP均存在),先判断user是否存在,ASP为例子:"select password from admin where user_nam ...
- 何为cookie?
何为cookie HTTP Cookie(也叫Web Cookie或浏览器Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上 ...
- PTA (Advanced Level) 1022 Digital Library
Digital Library A Digital Library contains millions of books, stored according to their titles, auth ...