从尾到头打印单链表(知道链表的头结点)
针对从尾到头打印链表,我们可以采用两种方式:
(1)利用栈的特性(先进后出),遍历链表将元素入栈,当链表为空时,依次出栈。
(2)采用递归方法,但是当数据量足够大时可导致栈溢出。
![这里写图片描述](https://img-blog.csdn.net/20180726141506115?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNDA5MTE1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
package com.struct.interview_question.list_interview_question;
public class ListNode {
public Object data;
public ListNode nextNode;
public ListNode(Object data) {
this.data = data;
}
}
package com.struct.interview_question.list_interview_question.listreverse;
import com.struct.interview_question.list_interview_question.ListNode;
import java.util.Stack;
public class ReverseList {
public static void printListReverseByStack(ListNode headNode){
Stack<ListNode> stack = new Stack<ListNode>();
while (headNode!=null){
stack.push(headNode);
headNode = headNode.nextNode;
}
while (!stack.isEmpty()){
System.out.print(stack.pop().data+" ");
}
}
public void printListReverseByRecursive(ListNode headNode){
if(headNode.nextNode!=null){
printListReverseByRecursive(headNode.nextNode);
}
System.out.print(headNode.data+" ");
}
}
本文中我将采用测试框架对代码进行测试。
step1:首先我们构建的Maven项目
step2:在pom文件中加入测试框架的依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
step3:进行测试
package com.struct.listinterview;
import com.struct.interview_question.list_interview_question.ListNode;
import com.struct.interview_question.list_interview_question.delete_headnode.DeleteNotTailNode;
import com.struct.interview_question.list_interview_question.listreverse.ReverseList;
import org.junit.Test;
public class ListInterviewQuestionTest {
@Test
public void test_PrintListReverseByStack(){
ReverseList reverseList = new ReverseList();
ListNode listNode = new ListNode(1);
listNode.nextNode = new ListNode("demon");
listNode.nextNode.nextNode = new ListNode('a');
reverseList.printListReverseByStack(listNode);
}
@Test
public void test_PrintListReverseByRecursive(){
ReverseList reverseList = new ReverseList();
ListNode listNode = new ListNode(1);
listNode.nextNode = new ListNode("demon");
listNode.nextNode.nextNode = new ListNode('a');
reverseList.printListReverseByRecursive(listNode);
}
不遍历链表,删除一个无头单链表的非尾节点
删除指定的非尾节点:
step1:我们首先创建一个新的节点curNode指定要删除节点的
下一个节点
step2:将此节点的值赋给要删除节点node
step3:将要删除节点node的下一个节点指向新建节点
的下一个节点curNode.next
![这里写图片描述](https://img-blog.csdn.net/20180726141530136?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNDA5MTE1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
package com.struct.interview_question.list_interview_question.delete_headnode
import com.struct.interview_question.list_interview_question.ListNode
public class DeleteNotTailNode {
//不遍历链表删除无头单链表的非尾节点(参数为要删除的节点)
public void deleteNotTailNode(ListNode node){
ListNode curNode = null
if(node.nextNode!=null) {
curNode = node.nextNode
node.data = curNode.data
node.nextNode = curNode.nextNode
}
}
}
@Test
public void test_DeleteNotTailNode(){
ListNode listNode = new ListNode(1);
listNode.nextNode = new ListNode("demon");
listNode.nextNode.nextNode = new ListNode('a');
DeleteNotTailNode deleteNotTailNode = new DeleteNotTailNode();
deleteNotTailNode.deleteNotTailNode(listNode.nextNode);
ReverseList reverseList = new ReverseList();
reverseList.printListReverseByRecursive(listNode);
}
在无头单链表的一个节点前插入新的节点
在节点前进行插入节点,我们并不能和以往一样改变节点的
指向就好,而是首先创建新的的节点newNode,使得节点指向
指定要插入节点node的下一个节点node.next,然后再使得node
指向新的节点newNode,最后,我们应当对node和newNode的值进行交换。
![这里写图片描述](https://img-blog.csdn.net/20180726141855635?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNDA5MTE1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
package com.struct.interview_question.list_interview_question.insertnode
import com.struct.interview_question.list_interview_question.ListNode
public class InsertNode {
//在无头链表的任意节点前插入节点(不遍历链表)
public void insertNodePre(ListNode node){
ListNode newNode = new ListNode("lll")
//新节点指向要插入节点的下一个节点
newNode.nextNode = node.nextNode
//指点节点指向新的节点
node.nextNode = newNode
//交换节点的值
Object curData = node.data
node.data = newNode.data
newNode.data = curData
}
}
@Test
public void test_InsertNodePre(){
ListNode listNode = new ListNode(1);
listNode.nextNode = new ListNode("demon");
listNode.nextNode.nextNode = new ListNode('a');
InsertNode insertNode = new InsertNode();
insertNode.insertNodePre(listNode.nextNode);
ReverseList reverseList = new ReverseList();
reverseList.printListReverseByRecursive(listNode);
}
单链表实现约瑟夫环(JosephCircle)
首先我们来解释一下约瑟夫:
约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。
从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,
数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列
step1:首先我们应该用单链表创建一个环
step2:设置环的长度,及要被淘汰的数字(从1开始计数),每次淘汰一个,我们应该改变tail的指向,
即tail.next = tail.next.next;
![这里写图片描述](https://img-blog.csdn.net/20180726141602852?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNDA5MTE1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
package com.struct.interview_question.list_interview_question.listjosephcircle;
import com.struct.interview_question.list_interview_question.ListNode;
public class ListJosephCircle{
public void listJosephCircle(int perNum, int exitNum, ListNode tail){
while(tail!=tail.nextNode){
for(int i =1 ;i < exitNum;i++)
tail = tail.nextNode;
System.out.println(tail.nextNode.data+" ");
tail.nextNode = tail.nextNode.nextNode;
}
System.out.println("幸运者为:"+tail.data);
}
}
@Test
public void test_ListJosephCircle(){
//构建约瑟夫环
ListNode head = new ListNode(0)
head.nextNode = new ListNode(1)
head.nextNode.nextNode = new ListNode(2)
head.nextNode.nextNode.nextNode = new ListNode(3)
head.nextNode.nextNode.nextNode.nextNode = new ListNode(4)
head.nextNode.nextNode.nextNode.nextNode.nextNode = new ListNode(5)
ListNode tail = head.nextNode.nextNode.nextNode.nextNode.nextNode
tail.nextNode = head
//调用方法
ListJosephCircle listJosephCircle = new ListJosephCircle()
listJosephCircle.listJosephCircle(6,2,tail)
}