一、设计思路
一种方式就是将单链表进行反转,然后打印出来,但是这种方式会破坏其结构!如果突然要求正向打印,那么就很麻烦,还要再反转回去;另外一种方式就是使用栈的方式实现。
二、代码
package linkedList;
import java.util.Stack;
/*
* 题目要求:
使用带head头的单向链表实现 –水浒英雄排行榜管理
完成对英雄人物的增删改查操作, 注: 删除和修改,查找可以考虑学员独立完成,也可带学员完成
第一种方法在添加英雄时,直接添加到链表的尾部
第二种方式在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示)
各大厂关于链表的面试题:
1.查找求单链表中有效节点的个数
2.单链表中的倒数第k个结点 【新浪面试题】
3.单链表的反转【腾讯面试题,有点难度】
4.从尾到头打印单链表 【百度,要求方式1:反向遍历 。 方式2:Stack栈】
5.合并两个有序的单链表,合并之后的链表依然有序【课后练习.】
*/
/*
1.对链表进行相关操作
*/
public class SingleLinkedListDemo {
public static void main(String[] args) {
// 初始化数据
HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
HeroNode hero2 = new HeroNode(2, "李逵", "黑旋风");
HeroNode hero3 = new HeroNode(4, "花和尚", "鲁智深");
HeroNode hero4 = new HeroNode(3, "孙二娘", "母夜叉");
SingleLinkedList linkedList = new SingleLinkedList();
/*****************0.链表基本的增删改查操作**********************/
// 增(无序)
System.out.printf("链表:\n");
linkedList.addToEnd(hero1);
linkedList.addToEnd(hero2);
linkedList.addToEnd(hero3);
linkedList.addToEnd(hero4);
// 增(有序)
// linkedList.addWithOrder(hero1);
// linkedList.addWithOrder(hero4);
// linkedList.addWithOrder(hero3);
// linkedList.addWithOrder(hero2);
// 删(输入序号删除节点)
// linkedList.delNode(2);
// 改
// linkedList.reviseNode(3, "李逵", "黑旋风");
// 查
linkedList.showLinkedList(); //显示链表信息
/**************************end*********************************/
/*****************1.各大厂的链表模块的面试题********************/
// 面试题:返回有效节点个数
// System.out.println(linkedList.getHeader());
// int validLength = getLength(linkedList.getHeader());
// System.out.printf("%s%d","有效链表长度为:", validLength);
// 新浪:返回倒数第k个节点
// int lastIndex = 3; //倒数第二个节点
// if(0<lastIndex && lastIndex<=validLength) {
// int paramIndex = validLength - lastIndex + 1;
// HeroNode reverseNode = getReverseNode(linkedList.getHeader(), paramIndex);
// System.out.printf("%s%d%s","\n\n倒数第",lastIndex,"个节点为:");
// System.out.println("no."+ reverseNode.number + "---" + reverseNode.name + "---" + reverseNode.nickName);
// }
// 腾讯面试题:单链表的反转
// System.out.printf("\n链表反转:\n");
// ReverseLinkedList(linkedList.getHeader());
// linkedList.showLinkedList(); //显示链表信息
// 百度面试题:反向打印单链表(1.链表反转,2.放到栈里)
// 只编写用栈实现的代码
System.out.printf("\n使用栈进行链表反转:\n");
stackReverseLinkedList(linkedList.getHeader());
/**************************end*********************************/
}
// 0.1 统计单链表中的有效节点个数
public static int getLength(HeroNode hero) { //经过static修饰过后的方法可以用类名直接调用,不用实例化一个对象后才调用
HeroNode temp = hero;
int length = 0;
while(true) {
if(temp.next==null) {
break;
}
temp = temp.next;
length++;
}
return length;
}
// 0.2 单链表中的倒数第k个结点 【新浪面试题】
public static HeroNode getReverseNode(HeroNode headNode, int number) {
HeroNode temp = headNode;
int count = 0;
while(true) {
if(number == count) {
break;
}
count++;
temp = temp.next;
}
return temp;
}
// 0.3 单链表的反转【腾讯面试题,有点难度】
// 除了头部head之外的节点都要反转
public static void ReverseLinkedList(HeroNode head) {
// 如果单链表不存在或者只有一个节点,则没有反转的必要
if(head.next == null || head.next.next == null) {
return;
}else {
// 初始化操作
HeroNode currentNode = head.next; //保存node.next数据
HeroNode nextNode = null; //暂存node.next.next数据
HeroNode newHead = new HeroNode(0,"",""); //临时的一个头节点,用于在暂存反转之后的数据
while(currentNode != null) {
nextNode = currentNode.next;
currentNode.next = newHead.next;
newHead.next = currentNode;
currentNode = nextNode;
}
head.next = newHead.next;
return;
}
}
//0.4 使用栈进行单链表的反转
public static void stackReverseLinkedList(HeroNode head) {
// 如果单链表不存在或者只有一个节点,则没有反转的必要
if(head.next == null || head.next.next == null) {
return;
}else {
HeroNode currentNode = head.next; //保存node.next数据
Stack<HeroNode> heroStack = new Stack<HeroNode>();
while(currentNode!=null) {
heroStack.push(currentNode);
currentNode = currentNode.next;
}
while(heroStack.size()>0) {
System.out.println(heroStack.pop());
}
}
}
}
/*
* 2.对单链表定义“增删改查”方法
*/
class SingleLinkedList {
HeroNode headNode = new HeroNode('0',"",""); //定义链表头部
// 2.0 返回链表的header
public HeroNode getHeader() {
return headNode;
}
// 2.1 追加数据到链表尾部(不排序)
public void addToEnd(HeroNode hero) {
HeroNode temp = headNode; //用于暂存节点
while (true) {
if(temp.next == null) { // 到达链表末端,退出程序。
break;
}
temp = temp.next;
}
temp.next = hero;
}
// 2.2 追加数据到链表(根据序号从小到大排序)
public void addWithOrder(HeroNode hero) {
HeroNode temp = headNode; //用于暂存节点
boolean flag = true; //false代表序号重复
while (true) {
if(temp.next == null) { // 到达链表末端,退出程序。
break;
}
// 判断有没有找到节点
if(temp.next.number > hero.number) {
flag = true; //已经找到节点了
break;
} else if(temp.next.number == hero.number) {
flag = false;
break;
}
temp = temp.next;
}
// 必须要到while外面去追加节点,否则在while里面会走不到加节点的那一步
if(!flag) {
System.out.printf("%s%d%s","error:英雄序号"+ hero.number +"已经存在");
return;
}
hero.next = temp.next;
temp.next = hero;
}
// 2.3 删除节点信息
public void delNode(int number) {
HeroNode temp = headNode; //用于暂存节点
while (true) {
if(temp.next == null) { // 到达链表末端,退出程序。
break;
}
if(temp.next.number == number) {
temp.next = temp.next.next;
}
temp = temp.next;
}
}
// 2.4 修改节点信息
public void reviseNode(int number, String name, String nickName) {
HeroNode temp = headNode; //用于暂存节点
while (true) {
if(temp.next == null) {
break;
}
if(temp.next.number == number) {
temp.next.name = name;
temp.next.nickName = nickName;
}
temp = temp.next;
}
}
// 2.5 查看链表数据
public void showLinkedList() {
HeroNode temp = headNode; //用于暂存节点
while(true) {
if(temp.next == null) {
break;
}
temp = temp.next;
System.out.println(temp);
}
}
}
/*
* 3.HeroNode->定义英雄人物。
* 属性:序号,名字,昵称以及下一个节点
*/
class HeroNode {
public int number;
public String name;
public String nickName;
public HeroNode next; //将new的HeroNode实例对象指向next
public HeroNode(int number, String name, String nickName) {
this.number = number;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "no."+ this.number + "---" + this.name + "---" + this.nickName;
}
}
三、结果
![](https://img-blog.csdnimg.cn/20200616235359239.png)
四、特别说明
代码有很多,不只是解决这个问题!其中还包括了单链表的实现,单链表的增删改查;以及包含了新浪,百度,腾讯的面试题!有些题目在前面的文章里有提到,有些没有提到。有兴趣的小伙伴自行查看!