单链表的反转与逆序打印
破坏单链表结构
- 方式一:利用栈的特点,破坏原始链表结构,把各个节点的数据压入栈中,然后出栈,此时的栈底层还是数组这种数据结构
//方法一:利用栈存储数据的特点完成倒叙输出
public static void reverse1(Node head) {
if (head != null) {
//创建一个栈对象
Stack<Node> stack = new Stack();//栈底层还是数组
for (Node temp = head; temp != null; temp = temp.getNext()) {
//把各个节点数据存入到栈对象中
stack.push(temp);
}
//输出栈中各个元素
while (stack.size() > 0){
System.out.println(stack.pop().getData());
}
}
}
栈底层结构
/**
* Adds the specified component to the end of this vector,
* increasing its size by one. The capacity of this vector is
* increased if its size becomes greater than its capacity.
*
* <p>This method is identical in functionality to the
* {@link #add(Object) add(E)}
* method (which is part of the {@link List} interface).
*
* @param obj the component to be added
*/
public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
- 方法二:根据方式一我们可以进一步联想,此时的栈是一个存储数据的容器,那么反过来这个容器也可以有我们自己创建,比如(数组,list,map)
//根据方法一,那我们可以联想到只要把单向链表的各个节点数据遍历放到一个容器里面,倒叙输出就可以了
//那个这个容器就可以是数组,list,map,栈底层实际是数组
public static void reverse2(Node head) {
if (head != null) {
//创建一个list对象
List<Node> list = new ArrayList<>();//ArrayList底层还是一个Object数组
for (Node temp = head; temp != null; temp = temp.getNext()) {
//把各个节点数据存入到list对象中
list.add(temp);
}
//输出list中各个元素
for (int i = list.size() - 1 ; i >= 0 ; i--) {
System.out.println(list.get(i).getData());
}
}
}
//根据方法一,那我们可以联想到只要把单向链表的各个节点数据遍历放到一个容器里面,倒叙输出就可以了
//那个这个容器就可以是数组,list,map,栈底层实际是数组
public static void reverse3(Node head) {
if (head != null) {
//创建一个map对象
Map<Integer,Node> map = new HashMap<>();
int index = 0;
for (Node temp = head; temp != null; temp = temp.getNext()) {
//把各个节点数据存入到list对象中
map.put(index,temp);
index++;
}
//输出map中各个元素
Set<Integer> set = map.keySet();
for (int i = set.size() - 1; i >= 0 ;i--) {
System.out.println(map.get(i).getData());
}
}
}
不破坏单链表结构
- 方式一:使用普通遍历的方式
//使用遍历的方式
public static void reverse5(Node head) {
Node pre = head;
Node cur = head.getNext();
Node temp;
while (cur != null){
temp = cur.getNext();
cur.setNext(pre);
pre = cur;
cur = temp;
}
head.setNext(null);
for (Node swap = pre; swap != null ; swap = swap.getNext()) {
System.out.println(swap.getData());
}
}
- 方式二:使用双指针思想,先使用一个fast指针指向链表最后一个元素,然后在使用一个slow指针一次遍历链表,把指插入到fast.next(类似于头插法)直到slow和fast相同时停止遍历。
//反转链表
public static ListNode reverseList1(ListNode head) {
if (head.next == null)return head;
ListNode fast = head;
while (fast.next != null){
fast = fast.next;
}
ListNode slow = head;
ListNode next = null,temp =null;
while (slow != fast){
next = slow.next;
temp = slow;
temp.next = fast.next;
fast.next = temp;
slow = next;
}
return fast;
}