从尾到头打印单链表(知道链表的头结点)
针对从尾到头打印链表,我们可以采用两种方式:
(1)利用栈的特性(先进后出),遍历链表将元素入栈,当链表为空时,依次出栈。
(2)采用递归方法,但是当数据量足够大时可导致栈溢出。
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+" " );
}
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
本文中我将采用测试框架对代码进行测试。
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);
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
不遍历链表,删除一个无头单链表的非尾节点
删除指定的非尾节点:
step1:我们首先创建一个新的节点curNode指定要删除节点的
下一个节点
step2:将此节点的值赋给要删除节点node
step3:将要删除节点node的下一个节点指向新建节点
的下一个节点curNode.next
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的值进行交换。
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
}
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
@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;
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);
}
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
@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)
}