Java数据结构-线性表之静态链表
静态链表的定义:
节点由一个一维数组和一个指针域组成,数组用来存放数据元素,而指针域里面的指针(又称游标)用来指向下一个节点的数组下标。
这种链表称之为静态链表。
链表中的数组第一个和最后一个位置须要特殊处理,不存数据。第一个位置(即数组0下标)的节点的指针用来存放备用链表的第一个节点的数组下标。
最后一个位置(即数组长度MaxSize-1下标)的节点的指针用来存放指向有数值的第一个数据元素的数组下标,相似于单链表的头结点。
静态链表的演示样例图:
以下举一个摘抄自《大话数据结构》的样例。来解释一下静态数据链表。

以下介绍静态链表的插入和删除操作:
这里我画了一张图,简单的描写叙述了一下。相信应该easy理解,例如以下:
相同删除的演示样例图例如以下:
以下贴一下我用Java实现的代码,主要功能仅仅实现了插入和删除操作:
package com.phn.datestructure;
/**
* @author 潘海南
* @Email 1016593477@qq.com
* @TODO 静态链表
* @date 2015年7月19日
*/
public class FOStaticList<E> {
//静态链表的长度
private int size;
//静态链表的容量,实际容量为capacity-2:capacity-头结点-备用头结点=capacity-2
private int capacity;
//备用链表的头结点
private FOStaticNode<E> backNode= null;
//备用链表在数组中的位置。默觉得第一个,即为0
private int backNodeIndex = 0;
//静态链表的头结点,即静态链表数据元素链的头结点
private FOStaticNode<E> headerNode = null;
//静态链表的存储数据元素的数组
private FOStaticNode<E>[] fosn = null;
//默认容量
private static final int DEFUALT_CAPACITY = 100;
public FOStaticList(){
this(DEFUALT_CAPACITY);
}
/**
* @TODO 带參构造函数。用来初始化赋值静态链表,并进行相关容量和大小的设置
* @param initialCapacity 静态链表的初始化容量
*/
public FOStaticList(int initialCapacity) {
this.init(initialCapacity);
this.setCapacity(initialCapacity);
this.setSize();
}
/**
* @TODO 初始化赋值静态链表。并设置静态链表的头结点和备用链表的头结点
* @param initialCapacity
*/
private void init(int initialCapacity) {
//推断给定的初始化參数是否合法
if (initialCapacity < 0) {
throw new RuntimeException("数组大小错误:" + initialCapacity);
}
fosn = new FOStaticNode[initialCapacity];
//给静态链表赋值,内部的e=null。而游标设置为i+1
for(int i = 0;i<initialCapacity-1;i++){
fosn[i] = new FOStaticNode<E>();
fosn[i].setCursor(i+1);
}
fosn[initialCapacity-1] = new FOStaticNode<E>();
//设置静态链表的头结点指向备用链表的数组下标,即initialCapacity-1的节点的游标为0
fosn[initialCapacity-1].setCursor(backNodeIndex);
//设置静态链表的头结点为headerNode
this.setHeaderNode(fosn[initialCapacity-1]);
//设置备用链表的头结点为backNode
this.setBackNode(fosn[backNodeIndex]);
}
/**
* @TODO 静态链表尾插法加入数据元素
* @param e 要加入的数据元素
* @return true
*/
public boolean add(E e){
//检查链表的容量,并进行对应的扩容
this.ensureCapacity(size);
//将备用链表头结点指向的游标(即备用链表的第一个位置)赋值给oldBackNodeCursor保存
int oldBackNodeCursor = this.backNode.getCursor();
if(size==0){
/*若眼下(即加入元素之前)静态链表没有数据元素,则将静态链表的头结点的游标指向
* “备用链表头结点指向的游标对应的位置”,即备用链表的第一个元素位置*/
this.headerNode.setCursor(oldBackNodeCursor);
}else{
//将静态链表的头结点指向的游标赋值给tempNodeCursor
int tempNodeCursor = this.headerNode.getCursor();
//以下的循环用来找到静态链表(数据元素链)的最后一个元素节点lastNode
FOStaticNode<E> lastNode = new FOStaticNode<E>();
while(tempNodeCursor!=0){
lastNode= this.fosn[tempNodeCursor];
tempNodeCursor= this.fosn[tempNodeCursor].getCursor();
}
//将lastNode节点的指向游标设置值为备用链表的第一个位置
lastNode.setCursor(oldBackNodeCursor);
}
//将备用链表的第一个位置设置数据元素为e
this.fosn[oldBackNodeCursor].setE(e);
//获取备用链表的第一个位置指向的游标,并将其赋值给newBackNodeCursor(作为新的备用链表头结点指向的游标)保存,
int newBackNodeCursor = this.fosn[oldBackNodeCursor].getCursor();
//设置备用链表的第一个位置(即眼下作为静态链表数据元素链的最后一个元素)指向的游标为备用链表的头结点位置(默认0位置)
this.fosn[oldBackNodeCursor].setCursor(backNodeIndex);
//设置备用链表头结点指向的游标为新的备用链表头结点指向的游标newBackNodeCursor
this.backNode.setCursor(newBackNodeCursor);
//链表长度加1
this.size++;
return true;
}
/**
* @TODO 依据提供的index来删除静态链表中的第index个元素
* @param index 静态链表中的第index个元素
* @return true or false
*/
public boolean remove(int index){
//推断给出的元素位置是否合法;this.capacity-2表示静态链表可以达到的最大长度:capacity-头结点-备用头结点=capacity-2
if(index<1 || index>this.capacity-2){
System.out.println("不存在此位置的元素");
return false;
}
//声明变量preRemoveCursor用来作为将要删除的数据元素数组的下标。或者称为将要删除的数据元素的前一个节点指向的游标。
int preRemoveCursor = this.headerNode.getCursor();
//以下的循环用来找出删除的数据元素的前一个节点preRemoveNode和将要删除的数据元素的前一个节点指向的游标preRemoveCursor
FOStaticNode<E> preRemoveNode = new FOStaticNode<E>();
int tempCount = 0;
while(tempCount!=index-1){
preRemoveNode = this.fosn[preRemoveCursor];
preRemoveCursor = preRemoveNode.getCursor();
tempCount++;
}
//声明变量oldBackNodeCursor作为备用链表的头结指向的游标并赋值保存。
int oldBackNodeCursor = this.backNode.getCursor();
//设置备用链表的头结点指向的游标为 将要删除的数据元素数组的下标 preRemoveCursor
this.backNode.setCursor(preRemoveCursor);
//将将要删除的数据元素指向的游标赋值给removeCursor并保存
int removeCursor = this.fosn[preRemoveCursor].getCursor();
//将将要删除的数据元素指向的游标设置为备用链表的头结指向的游标oldBackNodeCursor
this.fosn[preRemoveCursor].setCursor(oldBackNodeCursor);
//将将要删除的数据元素设置为null,即删除
this.fosn[preRemoveCursor].setE(null);
//将将要删除的数据元素的前一个节点指向的游标设置为将要删除的数据元素指向的游标removeCursor
preRemoveNode.setCursor(removeCursor);
//长度减1
this.size--;
return true;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer("[ ");
int currentCursor = this.headerNode.getCursor();
if(currentCursor!=backNodeIndex){
sb.append(currentCursor+""+this.fosn[currentCursor]);
currentCursor = this.fosn[currentCursor].getCursor();
while(currentCursor!=backNodeIndex){
sb.append(", "+currentCursor+""+this.fosn[currentCursor]);
currentCursor = this.fosn[currentCursor].getCursor();
}
}
return sb.append(" ]").toString();
}
/**
* @TODO 推断静态链表的容量是否超过,并进行对应的扩容操作。
* 注意:这里最基本的是将当前静态链表数组下标最后一个位置的游标保存起来。即将头结点指向的游标保存起来;
* 然后赋值给新的静态链表的头结点指向的游标。
* @param currentSize 当前长度
*/
private void ensureCapacity(int currentSize) {
if(currentSize == this.capacity-2){
int oldCapacity = this.capacity;
//这里我是依照ArrayList的扩容来进行的,扩大约1.5倍左右。
this.capacity = (this.capacity * 3) / 2 + 1;
FOStaticNode<E>[] newData = new FOStaticNode[this.capacity];
for (int i = 0; i < oldCapacity-1; i++) {
newData[i] = this.fosn[i];
}
newData[capacity-1] = new FOStaticNode<E>();
newData[capacity-1].setCursor(this.fosn[oldCapacity-1].getCursor());
for(int i = oldCapacity-1;i<this.capacity-1;i++){
newData[i] = new FOStaticNode<E>();
newData[i].setCursor(i+1);
}
this.fosn = newData;
}
}
/**
* @return the size
*/
public int size() {
return size;
}
private void setSize() {
this.size=0;
}
/**
* @param backNode the backNode to set
*/
private void setBackNode(FOStaticNode<E> backNode) {
this.backNode = backNode;
}
/**
* @param headerNode the headerNode to set
*/
private void setHeaderNode(FOStaticNode<E> headerNode) {
this.headerNode = headerNode;
}
/**
* @param capacity the capacity to set
*/
private void setCapacity(int capacity) {
this.capacity = capacity;
}
}
在举一个删除的演示样例图,请联系我的代码进行操作,
首先写个測试的方法
public static void main(String[] args) {
FOStaticList<String> fosl = new FOStaticList<String>(6);
fosl.add("元素1");
System.out.println(fosl);
fosl.add("元素2");
fosl.add("元素3");
System.out.println(fosl);
fosl.add("元素4");
System.out.println(fosl);
System.out.println(fosl.size());
fosl.remove(2);
System.out.println(fosl);
}
执行測试方法,结合下图应该可以比較好的理解。

最后说说静态链表的优缺点。

Java数据结构-线性表之静态链表的更多相关文章
- Java数据结构-线性表之单链表LinkedList
线性表的链式存储结构,也称之为链式表,链表:链表的存储单元能够连续也能够不连续. 链表中的节点包括数据域和指针域.数据域为存储数据元素信息的域,指针域为存储直接后继位置(一般称为指针)的域. 注意一个 ...
- [数据结构-线性表1.2] 链表与 LinkedList<T>(.NET 源码学习)
[数据结构-线性表1.2] 链表与 LinkedList<T> [注:本篇文章源码内容较少,分析度较浅,请酌情选择阅读] 关键词:链表(数据结构) C#中的链表(源码) 可空类 ...
- 【Java】 大话数据结构(3) 线性表之静态链表
本文根据<大话数据结构>一书,实现了Java版的静态链表. 用数组描述的链表,称为静态链表. 数组元素由两个数据域data和cur组成:data存放数据元素:cur相当于单链表中的next ...
- Java数据结构-线性表之顺序表ArrayList
线性表的顺序存储结构.也称为顺序表.指用一段连续的存储单元依次存储线性表中的数据元素. 依据顺序表的特性,我们用数组来实现顺序表,以下是我通过数组实现的Java版本号的顺序表. package com ...
- c数据结构链式存储-静态链表
#include "string.h" #include "ctype.h" #include "stdio.h" #include &qu ...
- javascript实现数据结构与算法系列:线性表的静态单链表存储结构
有时可借用一维数组来描述线性链表,这就是线性表的静态单链表存储结构. 在静态链表中,数组的一个分量表示一个结点,同时用游标(cur)代替指针指示结点在数组中的相对位置.数组的第0分量可看成头结点,其指 ...
- [数据结构 - 第3章] 线性表之单链表(C++实现)
一.类定义 单链表类的定义如下: #ifndef SIGNALLIST_H #define SIGNALLIST_H typedef int ElemType; /* "ElemType类型 ...
- [从今天开始修炼数据结构]线性表及其实现以及实现有Itertor的ArrayList和LinkedList
一.线性表 1,什么是线性表 线性表就是零个或多个数据元素的有限序列.线性表中的每个元素只能有零个或一个前驱元素,零个或一个后继元素.在较复杂的线性表中,一个数据元素可以由若干个数据项组成.比如牵手排 ...
- 玩转C线性表和单向链表之Linux双向链表优化
前言: 这次介绍基本数据结构的线性表和链表,并用C语言进行编写:建议最开始学数据结构时,用C语言:像栈和队列都可以用这两种数据结构来实现. 一.线性表基本介绍 1 概念: 线性表也就是关系户中最简单的 ...
随机推荐
- 菜鸟之路——机器学习之BP神经网络个人理解及Python实现
关键词: 输入层(Input layer).隐藏层(Hidden layer).输出层(Output layer) 理论上如果有足够多的隐藏层和足够大的训练集,神经网络可以模拟出任何方程.隐藏层多的时 ...
- LeetCode with Python -> String
344. Reverse String Write a function that takes a string as input and returns the string reversed. E ...
- 深入学习之mysql(四)聚合函数
聚合函数:COUNT统计记录的条数.SUM求和函数.AVG求平均值.MAX求最大值.MIN求最小值 一.COUNT练习: 1.统计学校一共有多少个学生: mysql> SELECT COUN ...
- linux VIM编辑器常用指令
一般模式 查看文本-移动光标 [Ctrl] + [f] 屏幕『向前』移动一页 [Ctrl] + [b] 屏幕『向后』移动一页 n<space> 按下数字后再按空格键,光标会向右移动这一 ...
- Redis实现缓存,你应该懂的哪些思路!
场景一:类似于微博,实现关注和被关注功能. 思路: 对每个用户使用两个集合类型键,用来存储关注别人的用户和被该用户关注的用户.当用户A关注用户B的时候,执行两步操作: sadd user:A B sa ...
- pdf生成(itextSharp)
最近在工作中遇到一个问题,客户要求将系统中的表格全部导出成PDF格式.经过搜索,基本是三种思路: 直接用byte写PDF文件.(算你狠,霸王硬上弓) 通过Com组件转换.以Adobe Acrobat为 ...
- 基里巴斯(path)
基里巴斯(path) 题目描述 最近,帕特里克沉迷于世界地图上的太平洋地区.他发现了一个名字奇异的岛国:基里巴斯共和国,简称基里巴斯,是一个太平洋岛国. 其由33个岛屿组成. "可惜它快被淹 ...
- 当时用vuex的时候,使用...对象展开扩展符报错的解决办法
出现这种问题的主要原因是当前的babel不支持...对象展开扩展符,只需要安装一个插件然后再在.babelrc当中进行下配置就好了 npm i babel-plugin-transform-objec ...
- Bzoj2829 信用卡凸包
Time Limit: 10 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 333 Solved: 155 Description Input ...
- 了解 Oracle Berkeley DB 可以为您的应用程序带来 NoSQL 优势的原因及方式。
将 Oracle Berkeley DB 用作 NoSQL 数据存储 作者:Shashank Tiwari 2011 年 2 月发布 “NoSQL”是在开发人员.架构师甚至技术经理中新流行的一个词汇. ...