线性表的链式存储和实现

链表的存储表示

  • 顺序表:静态存储分配,事先确定容量。

        链表:动态存储分配,运行时分配空间。

  • 元素(数据元素的映象) + 指针(指示后继元素存储位置)

         =  结点 (表示数据元素  或  数据元素的映象)

  • 以“结点的序列”表示的线性表称作链表。
  • 头指针、头结点和首结点

        头指针是指向链表中第一个结点(或为头结点或为首元结点)的地址。

        头结点是在链表的首元结点之前附设的一个结点;数据域内只放空表标志或表长等信息。

        首元结点是指链表中存储线性表第一个数据元素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)。

  1. 其它链表

循环链表: 最后一个结点的指针域的指针又指回第一个结点。

判空条件:head.next==head。

双向链表:

双向链表的结点类描述

public class DuLNode {

     public Object  data;    // 存放结点值的数据域

     public DuLNode prior; // 存放指向前驱结点的指针域

     public DuLNode next;   // 存放指向后继结点的指针域

}

posted @ 2021-12-09 15:13  阿留申要好好学习  阅读(211)  评论(0)    收藏  举报