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 概念: 线性表也就是关系户中最简单的 ...
随机推荐
- LeetCode——Problem3:Longest Substring Without Repeating Characters
哎哟我天啊.这道题快折磨死我了.刚开始连题都没看明白,就是不知道substring是什么意思.研究了好长时间才看出来的. 光辉历史呀...菜死了 1.题目 Given a string, find t ...
- linux基础(基本命令)
Linux学习 1.Linux安装.配置 Linux的操作背景介绍 Linux操作系统 开源.自由且开发源代码的类Unix操作系统 厂商较多 著名的有R ...
- 关于Android应用中图片占用内存浅谈
从事过移动端应用开发的童鞋应该都清楚,内存是非常宝贵的资源.如果能很好的利用有限的内存,对应用性能的提升会有很大的帮助.在实际应用开发中图片内存占整个应用非常大的比重,我们只有了解图片是如何加载到内存 ...
- Android EditText默认不弹出输入法,以及获取光标,修改输入法Enter键的方法
一.Android EditText默认不弹出输入法的办法:1. 在AndroidManifest.xml中将需要默认隐藏键盘的Activity中添加属性即可(常用此方法) android:windo ...
- 【Luogu】P2491消防(单调队列)
题目链接 首先可以想到路径一定是在直径上的. 然后对每个点dfs出不经过直径的以它开始的路径最大长度,记为dis 然后就可以求出直径之后枚举左右端点,设左端点l右端点r,直径上点距离直径上起点的距离用 ...
- P1463 [HAOI2007]反素数
题目描述 对于任何正整数x,其约数的个数记作g(x).例如g(1)=1.g(6)=4. 如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数.例如,整数1,2,4,6 ...
- POJ 3621 Sightseeing Cows(最优比例环+SPFA检测)
Sightseeing Cows Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 10306 Accepted: 3519 ...
- Java注解解析-搭建自己的注解处理器(CLASS注解使用篇)
该文章是继Java注解解析-基础+运行时注解(RUNTIME)之后,使用注解处理器处理CLASS注解的文章.通过完整的Demo例子介绍整个注解处理器的搭建流程以及注意事项,你将知道如何去搭建自己的注解 ...
- bzoj 4465 游戏中的学问(game)
题目描述 输入 输出 样例输入 3 1 1000000009 样例输出 2 提示 solution 令f[i][j]表示i个人围成j个圈的方案数 啥意思呢 可以把一个人塞进前面的圈里(i-1种塞法) ...
- 数组去重js方式
var selectmap = new Array(); /(\x0f[^\x0f]+)\x0f[\s\S]*\1/.test("\x0f"+selectmap.join(&quo ...