• 首页

  • 归档

  • 标签

  • 分类

  • 友链
M S B l o g
M S B l o g

ms

获取中...

04
16
java
总结

【数据结构】单向链表及Java的实现

发表于 2021-04-16 • java 总结 数据结构 • 被 900 人看爆

链表概念:

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。

单向链表:

  1. 概念:

链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
以“结点的序列”表示线性表称作线性链表(单链表),单链表是链式存取的结构

  1. 存储方式:

  • 用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的)
  • 链表中结点的逻辑次序和物理次序不一定相同。为了能正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址(或位置)信息(称为指针(pointer)或链(link))
    image.png

下图描述了单向链表存储情况。存储是分散的,每一个节点只要记录下一节点,就把所有数据串了起来,形成了一个单向链表。
image.png
节点(Node)是由一个需要储存的对象及对下一个节点的引用组成的。也就是说,节点拥有两个成员:储存的对象、对下一个节点的引用。下面图是具体的说明:
image.png

  1. 头节点,头指针和首元节点:

  • 头指针:一个普通的指针,它的特点是永远指向链表第一个节点的位置。很明显,头指针用于指明链表的位置,便于后期找到链表并使用表中的数据;
  • 节点:链表中的节点又细分为头节点、首元节点和其他节点:
    1. 头节点:其实就是一个不存任何数据的空节点,通常作为链表的第一个节点。对于链表来说,头节点不是必须的,它的作用只是为了方便解决某些实际问题;
    2. 首元节点:由于头节点(也就是空节点)的缘故,链表中称第一个存有数据的节点为首元节点。首元节点只是对链表中第一个存有数据节点的一个称谓,没有实际意义;
    3. 其他节点:链表中其他的节点;

因此,一个存储 {1,2,3} 的完整链表结构如图所示:

image.png

注意:链表中有头节点时,头指针指向头节点;反之,若链表中没有头节点,则头指针指向首元节点。

单向链表的实现:

链表中节点

 package linkedList;
/**
 * @ClassName: Node
 * @Description: 链表中节点,相当于火车的车厢
 * @author pms
 * @date 2021年4月16日
 *
 */

public class Node {
	/**
	 * 数据域
	 */
	protected long data;
	/**
	 * 指针域
	 */
	protected Node next;
	
	/**
	 * 构造其初始化参数
	 * 创建一个新的实例 Node
	 *
	 * @param value
	 */
	public Node(long value){
		this.data = value;
	}
	
	/**
	 * 
	 * @Title: display
	 * @Description: 显示方法
	 * @param  参数
	 * @return void 返回类型
	 * @throws
	 */
	public void display(){
		System.out.println(data + " ");
	}
}

单向链表

/**
 * @ClassName: LinkedList
 * @Description: 单向链表,相当于火车,定义里面之定义了头节点,就是因为可以通过指针域找到火车的车厢,即其他节点
 * @author pms
 * @date 2021年4月16日
 *
 */

public class LinkedList {
	/**
	 * 链表头节点
	 */
	private Node first;
	
	/**
	 * 初始化链表,不初始化也可以,因为编译器默认会给没初始化的属性赋值
	 * 创建一个新的实例 LinkedList
	 *
	 */
	public LinkedList(){
		first = null;
	}
	/**
	 * 
	 * @Title: empty
	 * @Description: 判断单链表是否为空
	 * @param @param value 新节点的值
	 * @return void 返回类型
	 * @throws
	 */
	public boolean empty(){
		return first.next == null;
	}
	/**
	 * 
	 * @Title: insertFirst
	 * @Description: 在头节点后面插入新节点
	 * @param @param value 新节点的值
	 * @return void 返回类型
	 * @throws
	 */
	public void insertFirst(long value){
		//构建新节点
		Node temp = new Node(value);
		//插入逻辑,next这个属性是protected类型,只能子类或者同包下可以引用
		temp.next = first;
		first = temp;
	}
	

	/**
	 * 
	 * @Title: addNode
	 * @Description: 添加节点到链表尾部
	 * @param @param value 参数
	 * @return void 返回类型
	 * @throws
	 */
	public void addNode(long value){
		//实例化一个节点
		Node newNode = new Node(value);
		//判断链表的头节点,如果为空,直接将新增的放到头节点
		if(first == null){
			first = newNode;
			return;
		}
		Node temp = first;
		//找到链表的末尾
		while(temp.next != null){
			temp = temp.next;
		}
		//找到末尾,添加新节点
		temp.next = newNode;
	}
	
	/**
	 * 
	 * @Title: deleteNode
	 * @Description: 删除第index个节点
	 * @param @param index
	 * @param @return 参数
	 * @return boolean 返回类型
	 * @throws
	 */
	public boolean deleteNode(int index){
		//参数不合理,直接返回false
		if(index < 0 || index > length() - 1){
			return false;
		}
		//删除头节点
		if(index == 0){
			first = first.next;
			return true;
		}
		int i = 0;
		Node preNode = first;
		Node curNode = preNode.next;
		while(curNode != null){
			if(i == index){
				preNode.next = curNode.next;
				return true;
			}
			preNode = curNode;
			curNode = curNode.next;
			i++;
		}
		return false;
	}
	
	/**
	 * 
	 * @Title: delete
	 * @Description: 删除指定节点
	 * @param @param n
	 * @param @return 参数
	 * @return boolean 返回类型
	 * @throws
	 */
	public boolean delete(Node n){
		//判断节点是否为空,或者是头节点,是则返回false
		if(n == null || n.next == null){
			return false;
		}
		long temp = n.data;
		n.data = n.next.data;
		n.next.data = temp;
		n.next = n.next.next;
		return true;
	}
	/**
	 * 
	 * @Title: length
	 * @Description: 返回链表的长度
	 * @param @return 参数
	 * @return int 返回类型
	 * @throws
	 */
	public int length(){
		int length = 0;
		Node temp = first; 
		while(temp != null){
			length ++;
			temp = temp.next;
		}
		return length;
	}
	/**
	 * 
	 * @Title: printLinkedList
	 * @Description: 输出该链表的各个节点
	 * @param  参数
	 * @return void 返回类型
	 * @throws
	 */
	public void printLinkedList(){
		Node temp = first;
		while(temp != null){
			System.out.print(temp.data + ", ");
			temp = temp.next;
		}
	}
}


分享到:
【力扣】移除重复节点
certbot安装https证书出现'ImportError: cannot import name UnrewindableBodyError'
  • 文章目录
  • 站点概览
ms

MSms

⚓️HelloWorld⚓️

QQ Email RSS
看爆 Top5
  • MyBatis-Plus分页查询 5,936次看爆
  • @Autowired与@Resource的区别 4,755次看爆
  • feign远程调用及异步调用丢失请求头问题 4,526次看爆
  • spring cloud中OpenFeign整合Sentinel启动报错 4,423次看爆
  • Certbot查看证书过期时间,手动续期以及自动续期 3,302次看爆

Copyright © 2025 ms · 湘ICP备20015239号

Proudly published with Halo · Theme by fyang · 站点地图