自行使用Java数组实现链表数据结构

这几年一直做企业ERP基础架构,对于算法领域的知识使用的较少,前两天被他人问及链表如何实现,草草在白板上写了一个一维字符串数组,用来表示链表,数组里面包含了一个长度为2的字符串数组,用来表示节点,节点的第一个元素保存值,第二个元素保存下个节点的引用,非常简单,但当时由于时间关系,没有仔细思考,草草作答了。

今天晚上,觉得有点时间,仔细想了下,应该采用面向对象的思想,对节点和链表高度抽象,节点应可以是任意对象。

首先让我们来复习下什么是链表?我们用一个简单的示意图表示(用画图板画了个,将就看吧:)):

[img]http://dl2.iteye.com/upload/attachment/0088/0850/019aecab-c7a3-3033-9c9d-eafd3d7d06dc.png[/img]

从上头可以看出,链表有如下特点:

1、有一个头和一个尾,一个有多个节点组成的非封闭的链

2、每个节点都有一个指针指向下一个节点

嗯,那我们要抽象一个链表的类,还要有一个节点的类,来实现上述链表的特点。

代码如下:


package com.iteye.redhacker.test;

/**
* 链表节点类
*
* @author JackDou
* @since 2013-08-11
*/
public class Node {

private Object value;

private Node next;

private int index;

public Node(Object value) {
this.value = value;
}

/**
* @return the value
*/
public Object getValue() {
return value;
}

/**
* @param value
* the value to set
*/
public void setValue(Object value) {
this.value = value;
}

/**
* @return the index
*/
public int getIndex() {
return index;
}

/**
* @param index
* the index to set
*/
public void setIndex(int index) {
this.index = index;
}

/**
* @return the next
*/
public Node getNext() {
return next;
}

/**
* @param next
* the next to set
*/
public void setNext(Node next) {
this.next = next;
}

@Override
public String toString() {
return "Node [index=" + index + "," + "value=" + value + "]";
}
}



package com.iteye.redhacker.test;

/**
* 链表类
*
* @author JackDou
* @since 2013-08-11
*/
public class LinkedList {

/** 默认容量大小及链表容量满的时候每次自动增加的大小 */
private static final int DEFAULT_CAPACITY_SIZE = 12;

/** 链表中的节点集合 */
private Node[] nodes;

/** 指针,指向链表末端待添加的位置,默认指向0的位置 */
private int endPos = 0;

/** 当前链表容量 */
private int capacity = 0;

public LinkedList() {
nodes = new Node[DEFAULT_CAPACITY_SIZE];
capacity = DEFAULT_CAPACITY_SIZE;
}

public LinkedList(int capacity) {
nodes = new Node[capacity];
this.capacity = capacity;
}

/**
* 链表大小
*
* @return 链表大小
*/
public int size() {
return endPos;
}

public int capacity() {
return this.nodes.length;
}

/**
* 向链表中加入一个节点
*
* @param node 新加入的节点
*/
public void add(Node node) {
if (this.endPos >= this.capacity() - 1) {
capacity = this.endPos + 1 + DEFAULT_CAPACITY_SIZE;
Node[] nodesTemp = new Node[capacity];
System.arraycopy(nodes, 0, nodesTemp, 0, this.endPos);
nodes = nodesTemp;
}
if (endPos == 0) {
node.setIndex(0);
nodes[endPos] = node;
} else if (endPos > 0 && endPos <= this.capacity() - 1) {
node.setIndex(endPos);
nodes[endPos] = node;
nodes[endPos-1].setNext(nodes[endPos]);
}
endPos++;
}

/**
* 删除链表元素
*
* @param index 要删除链表中节点的位置
*/
public void remove(int index) {
if (index > this.capacity() - 1 || index >= this.endPos || index < 0) {
throw new RuntimeException("没有位置索引" + index + "存在");
}
if (index == endPos-1) {
nodes[index] = null;
return;
}
for (; 0 <= index && index < endPos-1; index++) {
if (index == 0) {
nodes[index] = nodes[index+1];
nodes[index].setIndex(index);
} else {
nodes[index] = nodes[index+1];
nodes[index].setIndex(index);
nodes[index-1].setNext(nodes[index]);
}
}
endPos--;
}

/**
* 更新指定链表位置节点的值
*
* @param index 指定的链表位置
* @param value 指点链表位置上的节点的值
*/
public void update(int index, Object value) {
if (index > this.capacity() - 1 || index >= this.endPos || index < 0) {
throw new RuntimeException("没有位置索引" + index + "存在");
}
nodes[index].setValue(value);
}

/**
* 获取指点链表位置上的节点的值
*
* @param index 指定的链表位置
* @return 指点链表位置上的节点
*/
public Node getNode(int index) {
if (index > this.capacity() - 1 || index >= this.endPos || index < 0) {
throw new RuntimeException("没有位置索引" + index + "存在");
}
return nodes[index];
}

/**
* 在链表指定位置插入节点
*
* @param index 指定的链表位置
* @param value 节点
*/
public void insert(int index, Node node) {
if (index > this.capacity() - 1 || index >= this.endPos || index < 0) {
throw new RuntimeException("没有位置索引" + index + "存在");
}
if (this.endPos >= this.capacity() - 1) {
capacity = this.endPos + 1 + DEFAULT_CAPACITY_SIZE;
Node[] nodesTemp = new Node[capacity];
System.arraycopy(nodes, 0, nodesTemp, 0, this.endPos);
nodes = nodesTemp;
}
Node[] nodesTemp = new Node[size()- index];
System.arraycopy(nodes, index, nodesTemp, 0, nodesTemp.length);

for (int i = 0, len= nodesTemp.length; i< len; i++) {
nodesTemp[i].setIndex(nodesTemp[i].getIndex() + 1);
}
endPos++;
node.setIndex(index);
System.arraycopy(nodesTemp, 0, nodes, index+1, nodesTemp.length);
node.setNext(nodes[0]);
nodes[index] = node;
nodes[index-1].setNext(nodes[index]);
nodes[index].setNext(nodes[index+1]);
}

/**
* 获取链表的第一个节点
*
* @return 链表的第一个节点
*/
public Node getFirst() {
return nodes[0];
}

/**
* 获取链表的最后一个节点
*
* @return 链表的最后一个节点
*/
public Node getLast() {
return nodes[endPos-1];
}

/**
* 链表反序
*/
public LinkedList reverse() {
Node[] nodesTemp = new Node[capacity];
for (int i = 0, j = endPos - 1; i < endPos && j >= 0; i++, j--) {
nodesTemp[i] = nodes[j];
nodesTemp[i].setIndex(i);
if (j > 0) {
nodesTemp[i].setNext(nodes[j-1]);
}
}
nodes = nodesTemp;
return this;
}

public String toString() {
StringBuilder strBui = new StringBuilder();
for (int i = 0; i < endPos; i++) {
strBui.append(nodes[i].toString());
if (i < endPos) {
strBui.append(",");
}
}
return strBui.toString();
}

/**
* 获取当前链表容量
*
* @return the capacity
*/
public int getCapacity() {
return capacity;
}
}



package com.iteye.redhacker.test;

/**
* 测试类
*
* @author JackDou
* @since 2013-08-11
*/
public class Test {

public static void main(String[] args) {
// 创建默认大小的LinkedList
LinkedList list1 = new LinkedList();
list1.add(new Node(12));
list1.add(new Node(10));
list1.add(new Node(11));
list1.add(new Node(8));
list1.add(new Node(9));

System.out.println("链表默认容量为12");
System.out.println("链表长度:" + list1.size());
System.out.println("链表当前容量:" + list1.getCapacity());
System.out.println();

list1.add(new Node(2));
list1.add(new Node(4));
list1.add(new Node(5));
list1.add(new Node(7));
list1.add(new Node(6));
list1.add(new Node(1));
list1.add(new Node(3));

System.out.println("链表容量满时会自动扩容,默认为扩大12个节点容量");
System.out.println("链表:" + list1.toString());
System.out.println("链表第一个节点:" + list1.getFirst());
System.out.println("链表最后一个节点节点:" + list1.getLast());
System.out.println("链表长度:" + list1.size());
System.out.println("链表当前容量:" + list1.getCapacity());
System.out.println();

list1.remove(3);
System.out.println("删除索引为3的节点后的情况:");
System.out.println("链表:" + list1.toString());
System.out.println("链表第一个节点:" + list1.getFirst());
System.out.println("链表最后一个节点节点:" + list1.getLast());
System.out.println("链表长度:" + list1.size());
System.out.println("链表当前容量:" + list1.getCapacity());
System.out.println();

list1.add(new Node(80));
list1.add(new Node(90));
System.out.println("新增两个节点的情况(新增:80,90两个数字):");
System.out.println("链表:" + list1.toString());
System.out.println("链表第一个节点:" + list1.getFirst());
System.out.println("链表最后一个节点节点:" + list1.getLast());
System.out.println("链表长度:" + list1.size());
System.out.println("链表当前容量:" + list1.getCapacity());
System.out.println();

System.out.println("获取第8个节点的信息:" + list1.getNode(8));
System.out.println("获取第8个节点的下一个节点信息是:" + list1.getNode(8).getNext());
System.out.println();

System.out.println("测试反序链表");
System.out.println("原链表:" + list1.toString());
System.out.println("反序链表:" + list1.reverse().toString());
System.out.println();

System.out.println("链表长度:" + list1.size());
System.out.println("链表当前容量:" + list1.getCapacity());
System.out.println("测试在第3个索引的位置连续插入12个值为45的节点,使得链表长度超过当前容量,测试链表的自增长容量");
System.out.println("原链表:" + list1.toString());
list1.insert(3, new Node(45));
list1.insert(3, new Node(45));
list1.insert(3, new Node(45));
list1.insert(3, new Node(45));
list1.insert(3, new Node(45));
list1.insert(3, new Node(45));
list1.insert(3, new Node(45));
list1.insert(3, new Node(45));
list1.insert(3, new Node(45));
list1.insert(3, new Node(45));
list1.insert(3, new Node(45));
list1.insert(3, new Node(45));
System.out.println("插入后链表:" + list1.toString());
System.out.println("链表长度:" + list1.size());
System.out.println("链表当前容量:" + list1.getCapacity());
}
}


测试类打印出来的结果是:

[quote]
链表默认容量为12
链表长度:5
链表当前容量:12

链表容量满时会自动扩容,默认为扩大12个节点容量
链表:Node [index=0,value=12],Node [index=1,value=10],Node [index=2,value=11],Node [index=3,value=8],Node [index=4,value=9],Node [index=5,value=2],Node [index=6,value=4],Node [index=7,value=5],Node [index=8,value=7],Node [index=9,value=6],Node [index=10,value=1],Node [index=11,value=3],
链表第一个节点:Node [index=0,value=12]
链表最后一个节点节点:Node [index=11,value=3]
链表长度:12
链表当前容量:24

删除索引为3的节点后的情况:
链表:Node [index=0,value=12],Node [index=1,value=10],Node [index=2,value=11],Node [index=3,value=9],Node [index=4,value=2],Node [index=5,value=4],Node [index=6,value=5],Node [index=7,value=7],Node [index=8,value=6],Node [index=9,value=1],Node [index=10,value=3],
链表第一个节点:Node [index=0,value=12]
链表最后一个节点节点:Node [index=10,value=3]
链表长度:11
链表当前容量:24

新增两个节点的情况(新增:80,90两个数字):
链表:Node [index=0,value=12],Node [index=1,value=10],Node [index=2,value=11],Node [index=3,value=9],Node [index=4,value=2],Node [index=5,value=4],Node [index=6,value=5],Node [index=7,value=7],Node [index=8,value=6],Node [index=9,value=1],Node [index=10,value=3],Node [index=11,value=80],Node [index=12,value=90],
链表第一个节点:Node [index=0,value=12]
链表最后一个节点节点:Node [index=12,value=90]
链表长度:13
链表当前容量:24

获取第8个节点的信息:Node [index=8,value=6]
获取第8个节点的下一个节点信息是:Node [index=9,value=1]

测试反序链表
原链表:Node [index=0,value=12],Node [index=1,value=10],Node [index=2,value=11],Node [index=3,value=9],Node [index=4,value=2],Node [index=5,value=4],Node [index=6,value=5],Node [index=7,value=7],Node [index=8,value=6],Node [index=9,value=1],Node [index=10,value=3],Node [index=11,value=80],Node [index=12,value=90],
反序链表:Node [index=0,value=90],Node [index=1,value=80],Node [index=2,value=3],Node [index=3,value=1],Node [index=4,value=6],Node [index=5,value=7],Node [index=6,value=5],Node [index=7,value=4],Node [index=8,value=2],Node [index=9,value=9],Node [index=10,value=11],Node [index=11,value=10],Node [index=12,value=12],

链表长度:13
链表当前容量:24
测试caruso元素到第3个索引的位置连续插入12个值为45的节点,使得链表长度超过当前容量,测试链表的自增长容量
原链表:Node [index=0,value=90],Node [index=1,value=80],Node [index=2,value=3],Node [index=3,value=1],Node [index=4,value=6],Node [index=5,value=7],Node [index=6,value=5],Node [index=7,value=4],Node [index=8,value=2],Node [index=9,value=9],Node [index=10,value=11],Node [index=11,value=10],Node [index=12,value=12],
插入后链表:Node [index=0,value=90],Node [index=1,value=80],Node [index=2,value=3],Node [index=3,value=45],Node [index=4,value=45],Node [index=5,value=45],Node [index=6,value=45],Node [index=7,value=45],Node [index=8,value=45],Node [index=9,value=45],Node [index=10,value=45],Node [index=11,value=45],Node [index=12,value=45],Node [index=13,value=45],Node [index=14,value=45],Node [index=15,value=1],Node [index=16,value=6],Node [index=17,value=7],Node [index=18,value=5],Node [index=19,value=4],Node [index=20,value=2],Node [index=21,value=9],Node [index=22,value=11],Node [index=23,value=10],Node [index=24,value=12],
链表长度:25
链表当前容量:36
[/quote]

关于程序的详细实现这里不做详细的解释了,大家可以直接从文后下到源码,到如到eclipse里自行学习。

值得要说明的是:

1、我在链表里实现了一个反序,这是当时被问及的关键点,现在看起来似乎很简单的;
2、我在这个实现里使用了System.arraycopy()这个高级的API,或许还不够原生,有系统的同学可以实现自己的数组拷贝方法用以代替。

我的算法的复习因以此契机还需继续,希望有更多的时间去思考这些问题。加油!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值