Java链表基础

前记

最近又开始重新看数据结构和算法,算是还账吧。看到链表这觉得问题很多,网上的参考有些博主说法也不尽相同,于是刷了几道题找找思路和感觉,用Java总结了一下,毕竟网上大多都是C的(指针这问题感觉好多人也没完全搞懂,包括我)。

链表

首先,链表的存在就是为了解决顺序表不能解决的问题,即顺序表在插入一个节点的时候,在插入点后方的节点都要往后移动一位,因此时间复杂度在最好的情况下就是在最后的节点后面插入,时间复杂度为O(1),最坏情况就是在表头插入,时间复杂度为O(N),因此平均情况就是O(N/2)即O(N)。而链表因为有指针的缘故,在插入节点的时候,只需要调整插入点指针的指向。这里时间复杂度得看插入操作的数量级,比如我们在第n个位置插入操作,时间复杂度为O(n),然后再在n+1的位置插入,这时时间复杂度为O(1),因为n的位置已经知道了。而顺序表,我在第n个位置插入,后面的节点依次要往后移位,我在第n+1个位置插入,后面的节点还是需要移位。也就是说,和顺序表相比,链表更适合于频繁插入的情景。而顺序表的优势则在于访问节点时更快,时间复杂度为O(1),因为顺序表有索引。
而链表在访问某个节点的时候,我需要一个接一个的查找,而不能像顺序表那样有类似索引那样的东西。

链表节点
每个链表都是由若干节点构成:
在这里插入图片描述
那一个多个节点构成的单链表则长这个样子:
分为以下几种情况:
在这里插入图片描述
在这里要注意的是:每个链表必须有头指针(如上图的指针变量H),但是不一定有头节点,头结点的使用是为了处理一些极端情况,使得首元节点能够像其他节点一样用相同的处理方式。无论链表空还是非空,都必须有头指针。
若链表有头节点,那么头指针指向头节点,头节点指向链表的首元节点,即第一个含有数据域的节点,头节点的数据域一般为空,但有些情况下,头结点的数据域可以用来存放链表的长度等信息。若链表不含有头结点,那么头指针将指向首元结点。

单链表的相关操作

首先我们用一个java类来定义一个链表的节点:

	public class Node{
		int val = 0;
		Node next = null;
		public Node(int x){
			val = x;
		}
	}

1.初始化链表
没什么好说的,就好比你要定义一个整型变量 i,需要初始化:int n = 0;链表也一样。
这里我们可以定义一个链表类LinkList,初始化空链表其实就是空链表类的构造方法

public class LinkList {

    Node head;//头指针
    Node current; //当前节点
    int size; // 节点个数

    //初始化空链表
    public LinkList(){
        //初始化一个头结点,让头指针指向头结点。并且让当前节点独享等于头结点
        head = current = new Node(0);
        size = 0;
        head.next = head;

    }
}

2.其他操作

	/**
	*清空链表
	*/
	public void clearList(){
	//将头结点的next结点地址(即单链表的第一个结点的地址)置空,
	//则单链表会因缺少引用而被jvm回收,实现清空
		head.next = null;
    
	}

	/**
 	* 判断链表是否为空
 	* @return
 	*/
 	public void isEmpty(){
 		//这个和清空链表道理类似,如果头结点的next节点为空,那么就是一个空链表
 		return head.next == null;
 	}

	/**
     * 返回链表元素个数(链表长度)
     * @return int
     */
     public int listLength(){
     	//求链表长度必须要遍历所有元素
     	//我们可以用当前节点current遍历链表
     	int i;
     	//遍历终止条件就是当当前节点的下一节点为null时
     	for(i = 0;current.next != null ;i++){
     		current = current.next;
     	}
     	return i;
     }
     
 	/**
     * 返回单链表中指定位置元素的值
     * @param pos 位置
     * @return int 
     */
     public int getElem(int pos){
     	//这个和求链表长度类似,但是循环终止条件应为当到达pos位置时
     	//但是要注意不合法的输入,即pos < 0 或pos > size
     	if(pos < 0 || pos > size){
     		System.out.println("非法的输入")
     		}
     	//index == 0 则说明是头结点,则返回null
     	if (index == 0) {
            return null;
            }
     	for(int i = 0; i < pos; i++){
     		current = current.next;
     	}
     	return current.data;
     }
	/**
     * 返回单链表中第一个与指定值相同的元素的位置
     * @param val 指定值
     * @return 位置
     */
     public int getPos(int val){
		for(int i = 0;current.next != null ;i++){
			if(current.data == val){
				return i;
			}
			current = current.next;
		}
		return 0;//未找到返回0
	}

 	/**
     * 向指定位置插入节点
     * @param pos 位置
     * @param val 元素值
     */   
     public void insertNode(int pos,int data){
		//新插入的节点应指向原先位置的节点,原先位置的前一个节点要指向新插入的节点。最后,别忘了链表长度+1
		//图在最下面
		Node newNode = new Node(data);
		for(int i = 0; i < pos;i++){
			current = current.next;	
		}
		newNode.next = current.next;
		current.next = newNode;
		size ++;
		
		
	} 
 	/**
     * 删除操作 删除第pos个节点
     * @param pos 
     * @return
     */
     public void deleteNode(int pos){
		for(int i = 0;i < pos;i++){
			current = current.next;
		}
		//
		current.next = current.next.next;
		size -- ;
		
}


链表插入图示:
在这里插入图片描述

链表删除操作:
在这里插入图片描述

未完待续…

有不正确的地方欢迎批评指正~

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值