单向链表实现以及常见的面试题收录(java代码)
Java代码
package com.bingym.linkedlist;
import java.util.Stack;
public class SingleLinkedListByOrder {
//实现单向链表功能:链表的添加add(可以按照编号index进行插入),链表内容的打印
//内部需要包含一个节点类:内部类/外部类都可以
//定义单向链表的属性
private Node head =new Node(0,"");//该头结点不包含任何信息,只是作为单向链表的头结点标志,默认head的next域没有赋值,初始化为null
public Node getHead() {
return head;
}
//定义节点的添加方法:根据节点的index顺序进行节点的添加
public void addByOrder(Node node) {
//定义一个辅助指针变量:表示头结点head,因为头结点不能进行改变
Node temp = head;
//定义一个flag标志:表示新节点的编号在已存在的链表中是否存在
boolean flag = false;
//遍历链表
while (true) {
if (temp.next == null) {//表示当前链表为空
break;
}
if (temp.next.index > node.index) {//说明当前节点的下一个节点的index值大于新添加节点的index值,则直接在此处进行新节点的添加操作
break;
}else if (temp.next.index == node.index) {//说明当前节点的下一个节点的index值等于新添加节点的index值,则说明该index的节点已经存在,将flag置为true
flag = true;
break;
}
//此时上面条件都不满足,说明此时节点的index值小于新添加节点的index值,将temp节点向后平移
temp = temp.next;
}
//while循环以后,即找到了新节点添加的位置
if (flag) {
System.out.printf("您好,您想添加的index = %d的节点链表中已经存在,请添加其他节点\n",node.index);
}else {
//temp即为next域即为新添加节点的位置
//将新节点的next域指向temp节点的next域
node.next = temp.next;
//再将temp节点的next域指向新节点
temp.next = node;
}
}
//定义链表数据的显示操作
public void list() {
//首先在遍历之前判断链表是否为空
//抽取一个方法isEmpty()
if (isEmpty()) {
System.out.println("当前链表为空,没有节点元素可以进行显示");
return;
}
//否则说明链表存在节点数据
Node temp = head.next;
while (true) {
//判断当前节点是否到达链表的最后一个节点
if (temp == null) {
System.out.println();
break;
}
System.out.print(temp + "-->");
//将节点向后平移
temp = temp.next;
}
}
//判断链表是否为空
private boolean isEmpty() {
return head.next == null;
}
//根据传入节点的信息进行节点修改
public void update(Node newNode) {
//首先判断链表是否为空
if (isEmpty()) {
System.out.println("当前链表为空,无法找到修改节点信息");
return;
}
//若节点不为空,则进行节点的搜索工作
//定义查找标记flag
boolean flag = false;
Node temp = head.next;
while (true) {
if (temp == null) {
break;
}
if (temp.index == newNode.index) {
flag = true;
break;
}
temp = temp.next;//继续进行查找
}
//while循环结束
if (flag) {
temp.data = newNode.data;
}else {
//没有找到
System.out.printf("您好,您所要更新的index = %d的节点信息在链表中未找到\n",newNode.index);
}
}
//根据节点的index值删除对应的节点
public void remove(int index) {
if (isEmpty()) {
System.out.println("当前链表为空,无法进行删除操作");
return;
}
boolean flag = false;
Node temp = head;
while (true) {
if (temp.next == null) {
break;
}
if (temp.next.index == index) {
flag = true;
break;
}
temp = temp.next;
}
//此时若找到,temp的下一个节点即为要删除的节点
if (flag) {
temp.next = temp.next.next;
}else {
System.out.printf("您好,您所要删除的index = %d的节点信息在链表中未找到\n",index);
}
}
//根据节点的index获取指定的节点信息
public void find(int index) {
if (isEmpty()) {
System.out.println("当前链表为空");
}
boolean flag = false;
Node temp = head.next;
while (true) {
if (temp == null) {
break;
}
if (temp.index == index) {
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
System.out.println("您查找的的编号为" + index + "的节点信息为:" + temp);
}else {
System.out.println("您查找的编号为" + index + "节点信息不存在");
}
}
}
class Node {
//定义节点的属性
//data域,next域,编号index
public int index;
public String data;
public Node next;
public Node(int index, String data) {
this.index = index;
this.data = data;
}
@Override
public String toString() {
return "Node{" +
"index=" + index +
", data='" + data + '\'' +
'}';
}
}
单向链表常见的面试题
面试题1:获取单向链表有效节点的个数
//面试题1:查找链表有效节点的个数:不包括head
public int getSize() {
if (isEmpty()) {
return 0;
}
Node temp = head;
int size = 0;
while (true) {
if (temp.next == null) {//到达链表的最后一个节点
break;
}
size++;
temp = temp.next;
}
return size;
}
面试题2:查找链表中倒数第K个节点的信息
//面试题2:获取链表倒数第K个节点的信息
public Node findLastIndex(int k) {
//首先需要通过getSize()方法获取当前链表的有效节点的长度
//查找倒数第K个:即获取正序的第size - K:即有5个节点,倒数第3个,即正序的第2个
//找不到返回null
if (isEmpty()) {
return null;
}
int size = getSize();
Node temp = head.next;
if (k <= 0 || k > size) {
return null;
}
for (int i = 0; i < size - k; i++) {
temp = temp.next;
}
return temp;
}
面试题3:实现单向链表的反转(腾讯)
//面试题3:实现单链表的反转操作
public void reverseLinkList() {
if (head.next == null || head.next.next == null) {
//此时链表为空或者只要一个节点元素,反转以后链表不发生任何变化
return;
}
//定义一个新的头结点reverseHead,一个辅助指针变量指向当前节点,一个辅助指针变量指向当前节点的下一个节点
Node cur = head.next;
Node next = null;
Node reverseHead = new Node(0,"");
//遍历原链表
while (cur != null) {//说明当前链表没有遍历结束
next = cur.next;
cur.next = reverseHead.next;//将当前节点的next指向新头结点的next域[第一次cur.next = null]
reverseHead.next = cur;//将新头结点next指向新头结点
cur = next;//将cur节点进行向后平移
}
//遍历结束,新头结点指向的链表为原链表的反转链表
//此时将原头结点的next指向新头结点的next即最终完成原链表的反转
head.next = reverseHead.next;
}
面试题4:将单向链表实现逆向打印输出
//面试题4:实现单链表的逆向打印
//方式1:先将链表进行反转操作,在进行遍历打印
//方式2:利用栈的特性,先进后出,遍历单链表,将其依次入栈,然后再将栈中的数据进行出栈操作,不会破坏原有链表的结构
public void reversePrint() {
if (isEmpty()) {
System.out.println("{}");
return;
}
//创建一个节点的空栈
Stack<Node> stack = new Stack<>();
Node temp = head.next;
while (temp != null) {
stack.push(temp);
temp = temp.next;
}
//进行出栈打印工作
while (stack.size() > 0) {
System.out.print(stack.pop() + "-->");
}
}
面试题5:将两个有序的单向链表合并成一个依旧有序的单向链表
面试题5:将两个有序的单向链表进行合并,合并以后的链表依旧保持有序性
// //需要创建一个新的单向链表,用来存储合并以后的单链表数据
// //依次遍历两个单链表,将其中的节点按照index顺序进行添加
public static SingleLinkedListByOrder mergeLinkedList(Node head1,Node head2) {
//首先判断两个链表是否为空
//如果两个链表都为空,直接返回null
//如果两个链表其中一个为空,则合并以后的链表即为两个非空的链表
if (head1.next == null && head2.next == null) {
return null;
}
Node temp1 = head1.next;
Node temp2 = head2.next;
Stack<Node> stack = new Stack<>();
SingleLinkedListByOrder linkedList = new SingleLinkedListByOrder();
//依次遍历
while (temp1 != null) {
stack.push(temp1);
temp1 = temp1.next;
}
while (temp2 != null) {
stack.push(temp2);
temp2 = temp2.next;
}
//将栈中的所有节点按照index顺序进行添加到新的节点中
while (stack.size() > 0) {
linkedList.addByOrder(stack.pop());
}
return linkedList;
}