【数据结构】链表的实现

什么是链表?

之前我们学过的线性数据结构有动态数组丶栈和队列,这些数据结构底层都是依靠静态数组,靠resize解决容量问题;链表也是一种线性数据结构,但链表是最简单的真正的动态数据结构,链表可以辅助组成其他复杂的数据结构,学习链表可以更深入理解引用(指针)和递归。

优点:真正的动态,不需要处理动态容量问题

缺点:丧失了随机访问的能力(不能通过索引找到相应元素,因为不连续)

------------------------------------------------------------------------------------------------------------------------------------------------------------

添加元素

泛型类:LinkedList

内部类:Node

内部类成员变量:E e,Node next

成员变量(私有化):

int size,Node head

成员方法:

①获取链表元素个数   getSize()

②判断链表是否为空   isEmpty()

③在链表头添加元素   addFirst(E e)

④在链表中间的"index"位置上添加元素  add(int index,E e)

关键:找到待添加节点(node)的前一个节点(prev)

node.next=prev.next;

prev.next=node;

⑤在链表末尾添加元素   addLast(E e)

-------------------------------------------------------------------------------------------------------------------------------------

为链表设立虚拟头结点

前面我们看到,我们把在头节点添加元素和在链表中间添加元素区分开了,无非是在链表中间添加元素需要找到前一个节点,而头节点是没有前一个节点的,那么我们引用虚拟头节点(dummyHead),将这两种方法合二为一吧!

虚拟头节点不存储任何内容(null),但是指向头结点,即dummyHead.next=head,此时不需要头节点head,因为虚拟头结点指向的下一个节点就是头节点。

-------------------------------------------------------------------------------------------------------------------------------------------

链表的遍历丶查询和修改

①获取链表的第index个位置上的元素  get(int index)

②获取链表第一个元素  getFirst()

③获取链表最后一个元素  getLast()

④修改链表第index上的元素为e   set(int index,E e)

⑤查找链表在是否元素e   contains(E e)

------------------------------------------------------------------------------------------------------------------------------------------------

从链表中删除元素

删除指定“索引”上的元素,首先需要找到待删除节点(delNode)的前一个节点(prev),将前一个节点(prev)的下一个节点指向变为待删除节点(delNode)的下一个节点,这样就跳过了待删除节点,使待删除节点消失在链表中。

prev.next=delNode.next;

delNode.next=null;

①删除链表指定“索引”的元素  remove(int index)

②删除第一个元素   removeFirst()

③删除最后一个元素   removeLast()

--------------------------------------------------------------------------------------------------------------------------------------------------

链表操作时间复杂度分析

①添加操作

addLast(e)    O(n)

addFirst(e)    O(1)

add(int index,E e)   O(n)

②删除操作

removeLast()  O(n)

removeFirst()  O(1)

remove()         O(n)

③修改操作

set(int index,E e)  O(n)

contains(E e)    O(n)

总结:链表增删改查时间复杂度都为O(1),但是我们使用链表一般只对链表头进行操作,即复杂度为O(1)与数组操作相同,此时链表具有动态容量,不需要像动态数组那样浪费多余的内存空间。

-------------------------------------------------------------------------------------------------------------------------------------------------------------

链表源码

public class LinkedList<E> {
	/*
	 * 创建成员内部类(节点类)
	 */
	private class Node {
		public E e;
		public Node next;

		// 定义内部类构造方法
		public Node(E e, Node next) {
			this.e = e;
			this.next = next;
		}

		public Node(E e) {
			this(e, null);
		}

		public Node() {
			this(null, null);
		}

		@Override
		public String toString() {
			return e.toString();
		}
	}

	private Node dummyHead;// 虚拟头结点
	private int size;

	// 定义链表类的构造方法
	public LinkedList() {
		dummyHead = new Node(null, null);
		size = 0;
	}

	// 获取链表元素个数
	public int getSize() {
		return size;
	}
	// 返回链表是否为空

	public boolean isEmpty() {
		return size == 0;
	}

	// 在链表中间添加元素
	public void add(int index, E e) {
		if (index < 0 || index > size)
			throw new IllegalArgumentException("操作失败!索引位置有误!");

		Node prev = dummyHead;
		for (int i = 0; i < index; i++)
			prev = prev.next;
		prev.next = new Node(e, prev.next);
		size++;

	}

	// 在链表头添加元素
	public void addFirst(E e) {
		add(0, e);
	}

	// 在链表末尾添加元素
	public void addLast(E e) {
		add(size, e);
	}

	// 获取链表第index个位置上的元素
	public E get(int index) {
		if (index < 0 || index >= size)
			throw new IllegalArgumentException("操作失败!索引位置有误!");
		Node cur = dummyHead.next;
		for (int i = 0; i < index; i++)
			cur = cur.next;
		return cur.e;
	}

	// 获取链表第一个元素
	public E getFirst() {
		return get(0);
	}

	// 获取链表最后一个元素
	public E getLast() {
		return get(size - 0);
	}

	// 修改链表第index上的元素为e
	public void set(int index, E e) {
		if (index < 0 || index >= size)
			throw new IllegalArgumentException("操作失败!索引位置有误!");
		Node cur = dummyHead.next;
		for (int i = 0; i < index; i++)
			cur = cur.next;
		cur.e = e;
	}

	// 查找链表在是否元素e
	public boolean contains(E e) {
		Node cur = dummyHead.next;
		while (cur != null) {// 遍历链表
			if (cur.e.equals(e))
				return true;
			cur = cur.next;
		}
		return false;
	}

	// 删除链表第index上的元素
	public E remove(int index) {
		if (index < 0 || index >= size)
			throw new IllegalArgumentException("操作失败!索引位置有误!");
		Node prev = dummyHead;
		for (int i = 0; i < index; i++)
			prev = prev.next;
		Node delNode = prev.next;
		prev.next = delNode.next;
		delNode.next = null;
		size--;
		return delNode.e;
	}

	// 删除链表第一个节点(非虚拟头节点)
	public E removeFirst() {
		return remove(0);
	}

	// 删除链表最后一个节点
	public E removeLast() {
		return remove(size - 1);
	}

	@Override
	public String toString() {
		StringBuilder res = new StringBuilder();
		for (Node cur = dummyHead.next; cur != null; cur = cur.next)
			res.append(cur + "->");
		res.append("NULL");
		return res.toString();
	}
}

猜你喜欢

转载自blog.csdn.net/qq_42370146/article/details/82982184