算法通关村第一关——链表青铜挑战笔记

一、概念

(一)一些名词

链表:顾名思义,就是像链条一样,一节一节串起来的数据结构,每两小节的连接点被称之为链表的节点。
节点:链表中存储的每个元素称为节点,节点包括数据域和指针域。
数据域:数据域存储的是元素的值。
指针域:指针域存储的是当前元素与其前后元素之间的联系,简单来说就是前后元素的指针/内存地址。前后元素分别称为前驱节点和后继节点,其指针域分别称为前驱(prev)和后继(next)。
头结点:可以将链表的第一个节点作为头节点。
尾节点:可以将链表的最后一个节点作为尾节点。

(二)分类

链表可以简单分为单向链表、双向链表、循环链表、双向循环链表。

1、单向链表

特点:具有头节点,没有尾节点,最后一个节点通过头节点向后遍历访问。每个节点的指针域只有后继,没有前驱,只能单向遍历。最后一个节点的后继是null。
在这里插入图片描述

2、双向链表

特点:具有头节点和尾节点,每个节点的指针域包括前驱和后继,可以双向遍历(从头节点向尾节点遍历或者从尾节点向头节点遍历)。头节点的前驱和尾节点的后继都是null。
在这里插入图片描述

3、循环链表

特点:单向循环链表,在单向链表的基础上将最后一个节点的后继指向头节点。
在这里插入图片描述

4、双向循环链表

特点:在双向链表的基础上将头节点的前驱指向尾节点,将尾节点的后继指向头节点。
在这里插入图片描述

二、单向链表

(一)构造

public class Node<T>{
	// 数据域
	private T data;
	// 指针域:后继
	private Node next;
	public Node(T data){
		this.data = data;
	}
	public T getData() {
		return data;
	}
	public void setData(T data) {
		this.data = data;
	}
	public Node getNext() {
		return next;
	}
	public void setNext(Node next) {
		this.next = next;
	}
}

(二)插入

public Node insertNode(Node head, Node nodeInsert, int index) {
	// 获取当前链表的长度,此处未实现
	int size = getLength(head);
	if (index < 0 || index > size) {
		throw new IndexOutOfBoundsException();
	}
	// 首部插入
	if (index == 0) {
		nodeInsert.next = head;
		head = nodeInsert;
		return head;
	}
	// 中部插入
	Node tempNode = head;
	int count = 0;
	if (index > 0 && index < size) {
		while (count < index - 1) {
			tempNode = tempNode.next;
			count++;
		}
		nodeInsert.next = tempNode.next;
		tempNode.next = nodeInsert;
		return head;
	}
	// 尾部插入
	if (index == size) {
		while (count < index - 1) {
			tempNode = tempNode.next;
			count++;
		}
		tempNode.next = nodeInsert;
		nodeInsert.next = null;
		return head;
	}
}

(三)删除

public Node deleteNode(Node head, int index) {
	// 获取当前链表的长度,此处未实现
	int size = getLength(head);
	if (index < 0 || index >= size) {
		throw new IndexOutOfBoundsException();
	}
	// 头部删除
	if (index == 0) {
		head = head.next;
		return head;
	}
	// 中部删除
	if (index > 0 || index < size - 1) {
		Node tempNode = head;
		int count = 0;
		while (count < index - 1) {
			tempNode = tempNode.next;
			count++;
		}
		tempNode.next = tempNode.next.next;
		return head;
	}
	// 尾部删除
	if (index == size - 1) {
		Node tempNode = head;
		int count = 0;
		while (count < index - 1) {
			tempNode = tempNode.next;
			count++;
		}
		tempNode.next = null;
		return head;
	}
}

注意:单向链表插入和删除时,需要提前一个位置进行判断,即找到要插入或者删除节点的前驱节点进行操作。插入时,还需要先将新节点和原节点建立联系,然后再建立头节点或temp节点和新节点的联系,防止找不到原节点。

三、双向链表

(一)构造

public class Node<T> {
	private T data;
	private Node prev;
	private NOde next;

	public Node(T data, Node prev, Node next) {
		this.data = data;
		this.prev = prev;
		this.next = next;
	}

	public T getData() {
		return data;
	}
	public void setData(T data) {
		this.data = data;
	}
	public Node getPrev() {
		return prev;
	}
	public void setPrev(Node prev) {
		this.prev = prev;
	}
	public Node getNext() {
		return next;
	}
	public void setNext(Node next) {
		this.next = next;
	}
}

(二)插入

public Node insertNode(Node head, Node tail, Node nodeInsert, int index) {
	// 获取当前链表的长度,此处未实现
	int size = getLength(head);
	if (index < 0 || index >= size) {
		throw new IndexOutOfBoundsException();
	}
	// 头部插入
	if (index == 0) {
		nodeInsert.prev = null;
		nodeInsert.next = head;
		head.prev = nodeInsert;
		head = nodeInsert;
		return head;
	}
	// 中部插入
	if (index > 0 || index < size) {
		Node tempNode = head;
		int count = 0;
		while (count < index - 1) {
			tempNode = tempNode.next;
			count++;
		}
		// 将新节点与原节点双向连接起来
		nodeInsert.next = tempNode.next;
		tempNode.next.prev = nodeInsert;
		// 将原节点的前驱与新节点双向连接起来
		nodeInsert.prev = tempNode;
		tempNode.next = NodeInsert;
		return head;
	}
	// 尾部插入
	if (index == size) {
		tail.next = nodeInsert;
		nodeInsert.prev = tail;
		nodeInsert.next = null;
		return head;
	}
}

(三)删除

public Node deleteNode(Node head, Node tail, int index) {
	// 获取当前链表的长度,此处未实现
	int size = getLength(head);
	if (index < 0 || index >= size) {
		throw new IndexOutOfBoundsException();
	}
	// 头部删除
	if (index == 0) {
		head.next.prev = null;
		head = head.next;
		return head;
	}
	// 中部删除
	if (index > 0 && index < size) {
		Node nodeDelete = head;
		int count = 0;
		while (count < index) {
			nodeDelete = nodeDelete.next;
			count++;
		}
		nodeDelete.next.prev = nodeDelete.prev;
		nodeDelete.prev.next = nodeDelete.next;
		return head;
	}
	// 尾部删除
	if (index == size - 1) {
		tail.prev.next = null;
		tail = tail.prev;
		return head;
	}
}

以上内容皆为个人愚见,如有不足之处,还请不吝赐教。谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值