- 顺序表的局限性
(1)顺序表不可以很好地动态增加长度,如果需要扩充,则需要重新创建一个地址连续的更大的存储空间,并且需要把原来的数据拷贝到新的存储空间中;
(2)顺序表内部维护一个固定长度的数组,那也就是说在内存地址是连续的,如果要插入或者删除元素则会引起平均一半的元素移动。
因此顺表适合于“静态”的情况,一旦顺序表形成以后,很少对元素进行插入或者删除。 - 单链表的表示
(1)采用链式存储的线性表称为链表,链表中内个结点包含存放元素数值的数据域和存放逻辑上相邻结点的指针域。如果一个结点中只包含一个指针域称为单链表。
从图中可以得出如下结论:
1)单链表是通过后继结点的指针把它的一串结点连接成一个链;
2)线性表中第一个元素的存储地址作为线性表的起始地址,称作为线性表的头指针;
3)单链表中最后一个元素没有后继,所以它的指针域为null;
为了方便起见,在第一个结点之前虚加一个“头结点”,该头结点的数据域不存放具体的数值,指针域存放指向第一个结点的指针,指向头结点的指针称为单链表的头指针。如果线性表为空表,则头结点的指针域为空。 - 结点类的描述
单链表由多个结点组成,要实现单链表必须要设计结点类。
其中data表示的是当前结点的数据域,用来存放数值,next表示的是当前元素的指针域,用来存放后继结点的地址。以下为使用Java描述的结点类。
package dabao.wang;
public class Node {
private Node next; // 当前结点的指针域
private Object data; // 当前结点的数据域
public Node(Node nextval) { // 头结点
this.next = nextval;
}
public Node(Node nextval, Object data) {// 非空结点
this.next = nextval;
this.data = data;
}
public Node getNext() {// 获得当前结点的后继结点
return next;
}
public void setNext(Node next) {// 设置当前结点的后继结点
this.next = next;
}
public Object getData() {// 获得当前结点的数据
return data;
}
public void setData(Object data) {// 设置当前结点的数据
this.data = data;
}
@Override
public String toString() {
return this.data.toString();
}
}
- 单链表的描述
单链表需要设置一个头结点head,当前结点current,以及需要实现IList接口。
IList.java
package dabao.wang;
public interface IList {
public void clear(); // 清空顺序表
public boolean isEmpty();// 判读是否为空
public int length();// 获得顺序表的长度
public Object get(int index) throws Exception;// 获得下标为index的对象
public void insert(int index, Object x) throws Exception;// 在下标为index的位置插入元素x
public void remove(int index) throws Exception;// 移除下标为index的元素
public void display();// 遍历顺序表打印
}
LinkList.java
package dabao.wang;
public class LinkList implements IList {
private Node head;
private Node current;
private int size;
public LinkList() {
this.head = this.current = new Node(null);
this.size = 0;
}
// 定位函数,实现当前操作对象的前一个结点,也就是让当前结点对象定位到要操作结点的前一个结点。
private void indexOf(int index) throws Exception {
if (index < -1 || index > size - 1) {
throw new Exception("下标越界");
}
// 说明在头结点之后操作。
if (index == -1)
return;
current = head.getNext();
int j = 0;// 循环变量
while (current != null && j < index) {
current = current.getNext();
j++;
}
}
@Override
public void clear() {
this.head = null;
}
@Override
public boolean isEmpty() {
return this.size == 0;
}
@Override
public int length() {
return this.size;
}
@Override
public Object get(int index) throws Exception {
if (index < -1 || index > this.size - 1) {
throw new Exception("get函数下标越界");
}
indexOf(index);
return this.current.getData();
}
@Override
public void insert(int index, Object x) throws Exception {
if (index < 0 || index > this.size) {
throw new Exception("index函数下标越界");
}
indexOf(index - 1);// 定位到要操作结点的前一个结点对象。
this.current.setNext(new Node(this.current.getNext(), x));
this.size++;
}
@Override
public void remove(int index) throws Exception {
if (index < -1 || index > this.size - 1) {
throw new Exception("remove函数下标越界");
}
indexOf(index - 1);// 定位到要操作结点的前一个结点对象。
this.current.setNext(this.current.getNext().getNext());
this.size--;
}
@Override
public void display() {
Node tmp = head.getNext();
while (tmp.getNext() != null) {
System.out.print(tmp.getData() + " ");
tmp = tmp.getNext();
}
System.out.print(tmp.getData() + " ");
System.out.println();
}
}
- 测试单链表
Test.java
package dabao.wang;
public class Test {
public static void main(String[] args) throws Exception {
LinkList list = new LinkList();
for (int i = 0; i < 10; i++) {
int temp = ((int) (Math.random() * 100)) % 100;
list.insert(i, temp);
System.out.print(temp + " ");
}
System.out.println();
list.remove(4);
list.remove(5);
list.display();
}
}
测试结果: