线性表的链式存储和实现
链表的存储表示
- 顺序表:静态存储分配,事先确定容量。
 
链表:动态存储分配,运行时分配空间。
- 以元素(数据元素的映象) + 指针(指示后继元素存储位置)
 
= 结点 (表示数据元素 或 数据元素的映象)
- 以“结点的序列”表示的线性表称作链表。
 - 头指针、头结点和首结点
 
头指针是指向链表中第一个结点(或为头结点或为首元结点)的地址。
头结点是在链表的首元结点之前附设的一个结点;数据域内只放空表标志或表长等信息。
首元结点是指链表中存储线性表第一个数据元素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号