题目描述:
输入一个链表,反转链表后,输出链表的所有元素。
(hint : 请务必使用链表)
输入:
输入可能包含多个测试样例,输入以EOF结束。
对于每个测试案例,输入的第一行为一个整数n(0<=n<=1000):代表将要输入的链表的个数。
输入的第二行包含n个整数t(0<=t<=1000000):代表链表元素。
输出:
对应每个测试案例,
以此输出链表反转后的元素,如没有元素则输出NULL。
样例输入:
5
1 2 3 4 5
0
样例输出:
5 4 3 2 1
NULL
方法一:在下图中,结点 h , i , j 是相邻的三个结点,假设i之前的所有结点已经完成逆转,直接将i的下一个结点指向 h,很明显会发现链表断裂。因此必须将 i 的后一个结点保存,不然将遍历不到结点。因此需要三个指针,分别指向i的前一个结点,i 结点,以及 j 结点。
//遍历,将当前节点的下一个节点缓存后更改当前节点指针;
public static Node reverse(Node header){
if(header == null || header.getNextNode()==null)
return header;
//转化后的头结点
Node pReversedHeader = null;
//当前节点
Node pNode = header;
//当前节点前面的一个节点
Node pPrev = null;
while(pNode != null){
//将当前节点的下一个节点缓存,防止断开链
Node pNext = pNode.getNextNode();
//下一个节点为空,证明已经遍历到尾部节点,头结点指向它
if(pNext == null)
pReversedHeader = pNode;
//当前节点指向上一个节点
pNode.setNextNode(pPrev);
//更改当前节点,以及其上一个节点
pPrev = pNode;
pNode = pNext;
}
return pReversedHeader;
}
方法二:以头插法实现链表的反转,head指针始终指向第一个节点,从第一个结点开始一直将后续结点插入head之后。
//类似与头插法
public static Node reverse2(Node header){
if(header == null || header.getNextNode() == null)
return header;
Node p1=header;
Node p2=header.getNextNode();
while(p2!=null){
p1.setNextNode(p2.getNextNode());//记录下p的下一个节点
p2.setNextNode(header); //指向第一个节点
header=p2; //头结点始终指向第一个结点
p2=p1.getNextNode();//准备将p的下一个节点放到表头
}
return header;
}
实现代码:
package com.other.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
class Node {
private int value;
private Node nextNode;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Node getNextNode() {
return nextNode;
}
public void setNextNode(Node nextNode) {
this.nextNode = nextNode;
}
public Node(int value,Node nextNode) {
this.value = value;
this.nextNode = null;
}
}
public class ReverseList {
/**
* 反转链表
* 1、遍历,将当前节点的下一个节点缓存后更改当前节点指针;
* 2、类似与头插法
*/
//方法二:类似与头插法
public static Node reverse2(Node header){
if(header == null || header.getNextNode() == null)
return header;
Node p1=header;
Node p2=header.getNextNode();
while(p2!=null){
p1.setNextNode(p2.getNextNode());//记录下p的下一个节点
p2.setNextNode(header); //指向第一个节点
header=p2;
p2=p1.getNextNode();//准备将p的下一个节点放到表头
}
return header;
}
//方法一:遍历,将当前节点的下一个节点缓存后更改当前节点指针;
public static Node reverse(Node header){
if(header == null || header.getNextNode()==null)
return header;
//转化后的头结点
Node pReversedHeader = null;
//当前节点
Node pNode = header;
//当前节点前面的一个节点
Node pPrev = null;
while(pNode != null){
//将当前节点的下一个节点缓存,防止断开链
Node pNext = pNode.getNextNode();
//下一个节点为空,证明已经遍历到尾部节点,头结点指向它
if(pNext == null)
pReversedHeader = pNode;
//当前节点指向上一个节点
pNode.setNextNode(pPrev);
//更改当前节点,以及其上一个节点
pPrev = pNode;
pNode = pNext;
}
return pReversedHeader;
}
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
while(cin.nextToken()!=cin.TT_EOF){
int n = (int)cin.nval;
if(n==0){
System.out.println("NULL");
continue;
}
cin.nextToken();
Node header = new Node((int)cin.nval,null),current=header;
/*
* current用来操作当前节点的下一个节点;
* header不变,依然是指向第一个节点
* */
for(int i=0;i<n-1;i++){
cin.nextToken();
current.setNextNode(new Node((int)cin.nval,null));
current = current.getNextNode();
}
//Node reversedHeader = reverse(header);
Node reversedHeader = reverse2(header);
StringBuilder str = new StringBuilder();
while(reversedHeader!=null){
str.append(reversedHeader.getValue()+" ");
reversedHeader = reversedHeader.getNextNode();
}
System.out.println(str.substring(0, str.length()-1));
}
}
}