数据结构笔记_04 单链表(新浪、腾讯、百度面试题)

Questions:
1、求单链表中有效节点的个数
2、查找单链表中的倒数第k个节点【新浪面试题】
3、单链表的反转【腾讯面试题】(头插)
4、从尾到头打印单链表【百度,要求方式1:反向遍历。方式2: Stack栈】

一、求单链表中有效节点的个数

方法:获取到单链表的节点的个数。(如果是带头结点的链表,需要不统计头节点)

1)判断链表是否为空。
2)遍历链表。

	// head :链表的头节点 返回的就是有效节点的个数
	public static int getLength(HeroNode head) {
    
    
		if (head.next == null) {
    
    // 空链表
			return 0;
		}
		int length = 0;
		// 定义一个辅助的变量,这里我们没有统计头节点
		HeroNode cur = head.next;// 体现出没有统计头节点
		while (cur != null) {
    
    
			length++;
			cur = cur.next;// 遍历
		}
		return length;
	}

二、查找单链表中的倒数第k个节点

首先,因为是单链表,所以只能单向遍历链表,所以题目求倒数第几个节点,当转换成正数第几个。
例如:有3个有效节点(不包括头节点),求倒数第1个节点,转换过来就是让求正数第3个。

所以得到以下思路:
1、编写一个方法,接收head节点,同时接收一个 index。(index 表示是倒数第 index 个节点,就是题中的k)
2、先把链表从头到尾遍历,得到链表的总的长度。(getLength)
3、得到长度(size) 后,我们从链表的第一个开始遍历到第(size-index) 个,就可以得到。
4、如果找到了,则返回该节点,否则返回null

想一下这个方法需要几个参数?首先,需要一个待查单链表的头节点 head,其次需要题目中的 k。

	public static HeroNode findLastIndexNode(HeroNode head, int index) {
    
    
		// 判断如果链表为空,返回null
		if (head.next == null) {
    
    
			return null;// 没有找到
		}
		// 第一个遍历得到链表的长度(节点个数)
		int size = getLength(head);
		// 第二次遍历 size-index 位置,就是我们倒数的第k个节点
		// 先做一个index的校验
		if (index <= 0 || index > size) {
    
    
			return null;
		}// 定义一个辅助变量,for 循环定位到倒数的index
		HeroNode cur = head.next;// 3 //3 - 1 = 2
		for (int i = 0; i < size - index; i++) {
    
    
			cur = cur.next;
		}
		return cur;
	}

测试一下:查找倒数第二个节点。
在这里插入图片描述
在这里插入图片描述

结果如下:
在这里插入图片描述

三、单链表的反转

这里用到了头插法,示意图如下:

需要将数据2、5、9的节点,反转成9、5、2。
在这里插入图片描述
思路:
1.先定义一个节点 reverseHead = new HeroNode();
2.从头到尾遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表reverseHead 的最前端。(头插)
3.原来的链表的head.next = reverseHead.next

头插是啥意思,以下图为例:
我们需要将2号节点插入到reverseHead节点和1号节点之间。
1)将2号节点指向1号节点。(2号节点.next = reverseHead.next)
2)将reverseHead指向2号节点。(reverse.next = 2号节点)
只要做好这两步,就可以实现头插了。注意:这两步的顺序不能反。
在这里插入图片描述

按上图方法,操作三次就可以实现全部的头插了。

最后一步很关键,需要将反转后的链表,连接到原来的链表上。也就是

head节点->9 ->5->2

这样一个反转的链表。

最终示意图:
在这里插入图片描述
核心代码及注解:

		while (cur != null) {
    
    
			next = cur.next;// 先暂时保存当前节点的下一个节点,因为后面需要使用
			cur.next = reverseHead.next; /*将cur 的下一个节点指向新的链表的最前端(头插),不清楚的话
			想一想第一次,是将cur插入到头、空之间。【为了把原链表的节点的next数据清除,达到一次插入一个节点】*/
			reverseHead.next = cur;// 将cur 连接到新的链表上
			cur = next;// 让cur后移
		}
		// 将head.next 指向 reverseHead.next,实现单链表的反转。
		head.next = reverseHead.next;

while循环中的第2、3步,就是这张图,看着图想代码,灵思如泉涌。
在这里插入图片描述
完整源码:

	public static void reverseList(HeroNode head) {
    
    
		// 如果当前的链表为空,或者只有一个节点,无需反转,直接返回
		if (head.next == null || head.next.next == null) {
    
    
			return;
		}
		// 定义一个辅助的指针(变量),帮助我们遍历原来的链表
		HeroNode cur = head.next;
		HeroNode next = null;// 指向当前节点[cur]的下一个节点
		HeroNode reverseHead = new HeroNode(0, "", "");
		// 遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表reverseHead 的最前端
		while (cur != null) {
    
    
			next = cur.next;// 先暂时保存当前节点的下一个节点,因为后面需要使用
			cur.next = reverseHead.next; /*将cur 的下一个节点指向新的链表的最前端(头插),不清楚的话
			想一想第一次,是将cur插入到头、空之间。【为了把原链表的节点的next数据清除,达到一次插入一个节点】*/
			reverseHead.next = cur;// 将cur 连接到新的链表上
			cur = next;// 让cur后移
		}
		// 将head.next 指向 reverseHead.next,实现单链表的反转。
		head.next = reverseHead.next;
	}

测试一下:
在这里插入图片描述
结果如下:
在这里插入图片描述
成功将单链表反转!

四、从尾到头打印单链表

思路1:先反转,再遍历。这种方法会破坏原来的单链表的结构,不建议使用。
思路2:栈。先将各个节点压入栈中,再利用栈先进后出的特点,实现逆序打印。

举例如下:入栈:将jack、tom、smith三人依次压入栈中。出栈:smith、tom、jack依次出栈。
在这里插入图片描述
代码实现如下:

import java.util.Stack;

public class TestStack {
    
    
	public static void main(String[] args) {
    
    
		Stack<String> stack = new Stack();
		// 入栈
		stack.add("jack");
		stack.add("tom");
		stack.add("smith");

		System.out.println(stack.size());
		// 出栈
		while (stack.size() > 0) {
    
    
			System.out.println(stack.pop());// pop就是将栈顶的数据取出
		}
	}
}

测试结果如下:
在这里插入图片描述
下面,按照这个思路,利用栈实现从尾到头打印单链表:

	public static void reversePrint(HeroNode head) {
    
    
		if (head.next == null) {
    
    
			return;// 空链表,不能打印
		}
		// 创建一个栈,将各个节点压入栈
		Stack<HeroNode> stack = new Stack<HeroNode>();
		HeroNode cur = head.next;
		// 将链表的所有节点压入栈中
		while (cur != null) {
    
    
			stack.push(cur);
			cur = cur.next;// 让cur后移,这样就可以压入下一个节点
		}
		// 将栈中的节点进行打印
		while (stack.size() > 0) {
    
    
			System.out.println(stack.pop());// stack 的特点是先进后出
		}
	}

测试语句:
在这里插入图片描述
结果如下:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_45909299/article/details/113351436