线性表之链式存储结构
特点:
数据元素存储在不连续的存储空间。每个节点是由数据域和指针域组成。元素之间的逻辑关系通过存储节点之间的链接关系反映出来。
缺点:
- 比顺序存储结构的存储密度小(每个节点都由数据域和指针域组成,所以相同空间内假设全存满的话顺序存储比链式存储更多)。
- 查找节点时链式存储要比顺序存储慢(每个节点地址不连续、无规律、导致查找效率低下)。
优点:
- 插入、删除灵活(不必移动节点,只要改变节点中的指针,但是需要先定位到节点上)。
- 有元素才会分配节点空间,不会有闲置的节点。
手写LinkedList集合:
注意:java.util.LinkedList是双向链表,这里手写的LinkedList是单链表。
package com.bjsxt.datastructure.linetable;
/**
* 线性表接口
* 和存储结构无关
* @author Administrator
*
*/
public interface List {
// 返回线性表的大小,即数据元素的个数。
public int size();
// 返回线性表中序号为 i 的数据元素
public Object get(int i);
// 如果线性表为空返回 true,否则返回 false。
public boolean isEmpty();
// 判断线性表是否包含数据元素 e
public boolean contains(Object e);
// 返回数据元素 e 在线性表中的序号
public int indexOf(Object e);
// 将数据元素 e 插入到线性表中 i 号位置
public void add(int i, Object e);
// 将数据元素 e 插入到线性表末尾
public void add(Object e);
// 将数据元素 e 插入到元素 obj 之前
public boolean addBefore(Object obj, Object e);
// 将数据元素 e 插入到元素 obj 之后
public boolean addAfter(Object obj, Object e);
// 删除线性表中序号为 i 的元素,并返回之
public Object remove(int i);
// 删除线性表中第一个与 e 相同的元素
public boolean remove(Object e);
// 替换线性表中序号为 i 的数据元素为 e,返回原数据元素
public Object replace(int i, Object e);
}
Node.java:
package com.bjsxt.datastructure.linetable;
/**
* 单链表的结点
* @author Administrator
*
*/
public class Node {
//这里没有使用private是因为,可以直接通过点属性进行操作,注意这几个类在同一个包中
Object data;//要存储的数据
Node next; //指向下一个节点
public Node() {
}
public Node(Object data) {
super();
this.data = data;
}
public Node(Object data, Node next) {
super();
this.data = data;
this.next = next;
}
}
SingleLinkedList.java( 主要看add函数的实现):
package com.bjsxt.datastructure.linetable;
public class SingleLinkedList implements List{
private Node head = new Node();//头结点,不存储数据,为了编程方便
private int size;//一共有几个结点
@Override
public int size() {
return size;
}
@Override
public Object get(int i) {
//可就和顺序表不一样了,不能通过索引直接计算定位,而需要从头结点开始进行查找
Node p = head;
for(int j = 0;j<=i;j++){
p = p.next;
}
return p.data;
}
@Override
public boolean isEmpty() {
return size ==0;
}
@Override
public boolean contains(Object e) {
// TODO Auto-generated method stub
return false;
}
@Override
public int indexOf(Object e) {
// TODO Auto-generated method stub
return 0;
}
@Override
public void add(int i, Object e) {
//如果i位置错误报异常
if(i <0 || i> size){
throw new MyArrayIndexOutOfBoundsException("数组指针越界异常:"+i);
}
//找到前一个结点,从head结点开始
Node p = head;
for(int j = 0;j<i;j++){
p = p.next;
}
//新创建一个结点
//Node newNode = new Node(e);
Node newNode = new Node();
newNode.data = e;
//newNode.next = null;
//指明新结点的直接后继结点
newNode.next = p.next;
//指明新结点的直接前驱结点
p.next = newNode;
//size++
size++;
}
@Override
public void add(Object e) {
this.add(size, e);
}
@Override
public boolean addBefore(Object obj, Object e) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean addAfter(Object obj, Object e) {
// TODO Auto-generated method stub
return false;
}
@Override
public Object remove(int i) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean remove(Object e) {
// TODO Auto-generated method stub
return false;
}
@Override
public Object replace(int i, Object e) {
// TODO Auto-generated method stub
return null;
}
@Override
public String toString() {
if(size == 0){
return "[]";
}
StringBuilder builder = new StringBuilder("[");
Node p = head.next;
for(int i=0;i<size;i++){
if(i !=size -1){
builder.append(p.data+",");
}else{
builder.append(p.data);
}
//移动指针到下一个结点
p = p.next;
}
builder.append("]");
return builder.toString();
}
}
TestSingleList.java:
package com.bjsxt.datastructure.linetable;
public class TestSingleLinkedList {
public static void main(String[] args) {
List list = new SingleLinkedList();
list.add(123);
list.add(321);
list.add(456);
list.add(678);
list.add(789);
list.add(111);
list.add(222);
list.add(10, 666);
System.out.println(list.size());
System.out.println(list.isEmpty());
System.out.println(list.get(5));
System.out.println(list.toString());
}
}