线性表的链式存储和实现
链表的存储表示
- 顺序表:静态存储分配,事先确定容量。
链表:动态存储分配,运行时分配空间。
- 以元素(数据元素的映象) + 指针(指示后继元素存储位置)
= 结点 (表示数据元素 或 数据元素的映象)
- 以“结点的序列”表示的线性表称作链表。
- 头指针、头结点和首结点
头指针是指向链表中第一个结点(或为头结点或为首元结点)的地址。
头结点是在链表的首元结点之前附设的一个结点;数据域内只放空表标志或表长等信息。
首元结点是指链表中存储线性表第一个数据元素a0。
- 区别:
①有头结点(链表常用)
②无头结点(链式队列、链栈常用)
- 如何表示空表?
无头结点:head==NULL
有头结点:head.next==NULL
- 在链表中设置头结点有什么好处?
其作用是为了对链表进行操作时,可以对空表、非空表的情况以及对首元结点进行统一处理,便于插入、删除操作。
链表类的描述
结点类的描述
查看代码
package LinearList;
public class Node {
public Object data;
public Node next;
public Node() {
this(null,null);
}
public Node(Object data) {
this(data,null);
}
public Node(Object data,Node next) {
this.data=data;
this.next=next;
}
}
单链表类的描述
查看代码
public class LinkList implements IList{
public Node head;
public LinkList() {
head = new Node();
}
public LinkList(int n,boolean Order) throws Exception{
this();
if(Order)
create1(n); //尾插法
else
create2(n); //头插法
}
}
单链表基本操作的实现
查看代码
package LinearList;
import java.util.Scanner;
public class LinkList implements IList{
public Node head;
public LinkList() {
head = new Node();
}
public LinkList(int n,boolean Order) throws Exception{
this();
if(Order)
create1(n);
else
create2(n);
}
public void create1(int n) throws Exception{//尾插法
Scanner sc =new Scanner(System.in);
for(int j =0;j<n;j++)
insert(getLength(),sc.next());
}
public void create2(int n) throws Exception{//头插法
Scanner sc =new Scanner(System.in);
for(int j =0;j<n;j++)
insert(0,sc.next());
}
public void clear() {
head.data=null;
head.next=null;
}
public boolean isEmpty() {
return head.next==null;
}
public int getLength() {
Node p=head.next;
int length=0;
while(p!=null){
p=p.next;
++length;
}
return length;
}
public Object getValue(int i)throws Exception{
Node p=head.next;
int j=0;
while(p!=null&j<i) {
p=p.next;
++j;
}
if(i<0 || p==null) {
throw new Exception("第"+i+"个元素不存在");
}
return p.data;
}
public void insert(int i,Object x)throws Exception{
Node p=head;
int j=-1;
while(p!=null && j<i-1) {
p=p.next;
++j;
}
if(i<0 || p==null)
throw new Exception("插入位置不合法");
Node s=new Node(x);
s.next=p.next;
p.next=s;
}
public void remove(int i)throws Exception{
Node p=head;
int j=-1;
while(p.next!=null && j<i-1) {
p=p.next;
++j;
}
if(i<0 || p.next==null)
throw new Exception("删除位置不合法");
p.next=p.next.next;
}
public int indexOf(Object x) {
Node p=head.next;
int j=0;
while(p!=null && !p.data.equals(x)) {
p=p.next;
++j;
}
if(p!=null)
return j;
else
return -1;
}
public void display() {
Node p=head.next;
while(p!=null) {
System.out.println(p.data);
p=p.next;
}
}
}
算法分析
按位序号查找:单链表是一种"顺序存取"的结构,即为取第 i 元素,必须先找到第 i-1 个元素,所以要从头遍历。
按值查找:从头遍历,没找完返回位序号,找完没找到返回-1。
时间复杂度都是O(n)。
插入操作:带头结点。
1.查找第i个结点的前驱结点,确定待插入的位置。
初始状态:p = head ;j = -1;
注意不能改成p=head.next; j=0;否则不能对表头操作。
2.产生新结点S
3.修改链指针,注意先连结后断开。
s.next= p.next; p.next=s;
时间复杂度O(n)。
删除操作:带头结点。
1.查找第i个结点的前驱结点。初始状态与插入操作相同。
2.next=p.next.next。
时间复杂度O(n)。
建立操作:
头插法(逆位序法):创建的新结点插入到当前形成的单链表的表头。
尾插法(顺序法):创建的新结点插入到当前形成的单链表的表尾。
时间复杂度都是O(n)。
- 其它链表
循环链表: 最后一个结点的指针域的指针又指回第一个结点。
判空条件:head.next==head。
双向链表:
双向链表的结点类描述
public class DuLNode {
public Object data; // 存放结点值的数据域
public DuLNode prior; // 存放指向前驱结点的指针域
public DuLNode next; // 存放指向后继结点的指针域
}

浙公网安备 33010602011771号