新浪、百度、腾讯的单链表面试题
单链表常见的面试题如下:
- 求单链表中有效结点的个数
- 查找单链表中的倒数第k个结点【新浪面试题】
- 单链表的反转【腾讯面试题】
- 从尾到头打印单链表【百度,要求方式1:反向遍历。方式2:Stack栈】
- 合并两个有序的单链表,合并之后的链表依然有序
第一题
思路分析:
直接定义一个辅助变量来遍历单链表并且记录单链表长度,注意带头结点的单链表应该去掉头结点
代码实现如下:
// 获取单链表有效结点的个数(如果是带头结点的链表,需要将头结点去掉)
/*
* head是链表的头结点 返回的是单链表中有效结点的个数
*/
public static int getLength(HeroNode head) {
if (head.next == null) { //单链表为空,返回0
return 0;
}
int length = 0;
// 定义一个辅助的变量,这里没有统计头结点
HeroNode cur = head.next;
while (cur != null) {
length++;
cur = cur.next;
}
return length;
}
测试代码如下:
// 测试单链表有效结点的个数
System.out.println("有效的节点个数=" + getLength(singleLinkedList.getHead()));
第二题
思路分析:
- 首先在管理单链表的类中编写一个方法用来接收head结点,同时接收一个index
- index表示的是倒数第index个结点
- 先把链表从头到尾遍历一下,得到链表的总长度getLength
- 得到size后,我们从链表的第一个开始遍历(size-index)个,便得到倒数第index个结点
代码实现如下:
public HeroNode getHead() {
return head;
}
public static HeroNode findLastIndexNode(HeroNode head, int index) {
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;
for(int i=0; i<size-index; i++) {
cur = cur.next;
}
return cur;
}
测试代码如下:
//测试一下看看是否得到了倒数第k个结点
HeroNode res = findLastIndexNode(singleLinkedList.getHead(),1);
System.out.println("res=" + res);
第三题
思路分析:
- 先定义一个结点reverseHead = new HeroNode();
- 从头到尾遍历原来的链表,每遍历一个结点,就将其取出,并放在新的链表的最前端
- 原来的链表的head.next = reverseHead.next【头插法】
代码实现如下:
//将单链表进行反转
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; //将next指向cur.next,先暂时保存当前结点的下一个结点,因为后面需要使用
cur.next= reverseHead.next; //将cur的下一个结点指向新的链表的最前端
reverseHead.next = cur;
cur = next; //让cur指向next
}
//将head.next指向reverseHead.next,实现单链表的反转
head.next = reverseHead.next;
}
测试代码如下:
// 创建一个链表
SingleLinkedList singleLinkedList = new SingleLinkedList();
// 加入
singleLinkedList.add(hero1);
singleLinkedList.add(hero2);
singleLinkedList.add(hero3);
singleLinkedList.add(hero4);
//测试单链表反转
System.out.println("原来链表的情况");
singleLinkedList.list();
System.out.println("反转单链表");
reverseList(singleLinkedList.getHead());
singleLinkedList.list();
第四题
思路分析:
- 要求逆序打印单链表
- 方式1:先将单链表进行反转操作,然后进行遍历即可(问题:会破坏原来的单链表的一个结构)
- 方式2:可以利用栈这个数据结构,将各个结点压入栈中,然后利用栈的先进后出的特性,就实现了逆序打印的效果
栈的代码实现:
package com.linklist;
import java.util.Stack;
//用来演示栈Stack的基本使用
public class TestStack {
public static void main(String[] args) {
Stack<String> stack = new Stack();
//入栈
stack.add("jack");
stack.add("tom");
stack.add("smith");
//出栈
//smith,tom,jack
while(stack.size() > 0) {
System.out.println(stack.pop());//将栈顶的数据取出
}
}
}
第四题代码实现如下:
//使用栈的方式逆序打印单链表中的数据
public static void reversePrint(HeroNode head) {
if(head.next == null) {
return; //空链表无法打印
}
//创建一个栈,将各个结点压入栈中
Stack<HeroNode> stack = new Stack();
HeroNode cur = head.next;
//将链表的所有结点压入栈中
while(cur != null) {
stack.push(cur);
cur = cur.next; //让cur后移
}
//将栈中的结点进行打印,pop出栈
while(stack.size() > 0) {
System.out.println(stack.pop()); //先进后出
}
}
测试代码如下:
//测试逆序打印单链表
System.out.println("原来的链表结构");
singleLinkedList.list();
System.out.println("测试逆序打印单链表,没有改变链表本身的结构");
reversePrint(singleLinkedList.getHead());
第五题
思路分析:
定义一个新的链表,遍历并比较原来两个链表中编号最小的结点,并将最小的结点添加到新的链表中