Java 利用棧來反轉鏈表和排序的操作

棧是一個特殊的數據結構,特點是先進後出(First In Last Out 簡稱FILO),這種特殊的數據結構,可以用在對鏈表做反轉中,或者字符串逆序,因為要把頭變成尾,尾變成頭,棧這種結構最合適不過瞭,下面來看看如何用棧來做鏈表的反轉。

package com.xxx.algorithm.sort;
import java.util.Stack;
public class LinkedListReverse { 
 public static Node reverseLinkedList(Node head){
 Stack<Node> stack = new Stack<Node>();
 while(head!=null){
 stack.push(head);
 head = head.next;
 }
 if(!stack.isEmpty())
 head = stack.pop();
 Node cur = head;
 while(!stack.isEmpty()){
 Node node = stack.pop();
 node.next = null;
 cur.next = node;
 cur = node;
 }
 return head;
 }
 
 public static void display(Node head){
 System.out.print("list:");
 Node cur = head;
 while(cur!=null){
 System.out.print(cur+"->");
 cur = cur.next;
 }
 System.out.println();
 }
 
 public static void main(String[] args) {
 Node a = new Node("a");
 Node b = new Node("b");
 Node c = new Node("c");
 Node d = new Node("d");
 Node e = new Node("e");
 Node f = new Node("f");
 Node g = new Node("g");
 a.next = b;
 b.next = c;
 c.next = d;
 d.next = e;
 e.next = f;
 f.next = g;
 System.out.println("原始鏈表:");
 display(a);
 Node head = reverseLinkedList(a);
 System.out.println("反轉之後的鏈表:");
 display(head);
 }
}
 
class Node{
 String val;
 Node next;
 public Node(String val) {
 this.val = val;
 }
 @Override
 public String toString() {
 return "Node("+this.val+")";
 }
}

運行程序,結果如下:

原始鏈表:

list:Node(a)->Node(b)->Node(c)->Node(d)->Node(e)->Node(f)->Node(g)->

反轉之後的鏈表:

list:Node(g)->Node(f)->Node(e)->Node(d)->Node(c)->Node(b)->Node(a)->

通過棧來反轉鏈表思路很簡單,這隻是說瞭棧作為一種數據結構,其實用途很廣泛。今天要介紹的另外一個棧的用途是如何通過棧來排序,利用棧來排序,需要有兩個棧,一個存放原始數據,一個是輔助排序用的。

具體思路就是:將棧中的數據依次放入輔助棧中,放入輔助棧的要求是按照數據從大到小的排列(或者從小到大),先進入的是較大的數,後進入的是較小的數,如果原棧中沒有數據瞭,說明數據已經在輔助棧中排好序瞭,接著我們把數據再一次性放入原棧中,如果遍歷,就是一個排好序的數組瞭。

這裡面把原棧中的數據放入輔助棧中,需要借助一個中間變量,原棧中彈出的數據放入中間變量中,而不是直接入輔助棧,如果棧頂的元素小於中間變量,那麼將小於的數據再放入原棧中,再將中間變量放入輔助棧,接著再將原棧中的數據放入輔助棧,直到原棧為空。將中間變量放入輔助棧,類似插入排序,需要找到一個合適的位置,而移動出一個合適的位置,就是把輔助棧中的數據再次壓入原棧中。

算法示例代碼如下:

package com.xxx.algorithm.sort;
import java.util.Iterator;
import java.util.Stack;
public class StackSortDemo {
 
 public static void sortByStack(Stack<Integer> stack){
 Stack<Integer> help = new Stack<Integer>();
 while(!stack.isEmpty()){
 int cur = stack.pop();
 while(!help.isEmpty()&&help.peek()<cur){
 stack.push(help.pop());
 }
 help.push(cur);
 }
 while(!help.isEmpty()){
 stack.push(help.pop());
 }
 }
 
 public static void display(Stack<Integer> stack){
 System.out.print("stack:");
 Iterator<Integer> it = stack.iterator();
 while(it.hasNext()){
 System.out.print(it.next()+"->");
 }
 System.out.print("null");
 System.out.println();
 }
 
 public static void main(String[] args) {
 Stack<Integer> stack = new Stack<Integer>();
 stack.push(2);
 stack.push(9);
 stack.push(5);
 stack.push(4);
 stack.push(6);
 stack.push(3);
 stack.push(8);
 stack.push(7);
 System.out.println("原始棧:");
 display(stack);
 sortByStack(stack);
 System.out.println("排序之後的棧:");
 display(stack); 
 }
}

運行程序,打印信息如下:

原始棧:

stack:2->9->5->4->6->3->8->7->null

排序之後的棧:

stack:2->3->4->5->6->7->8->9->null

補充:Java數據結構與算法——-鏈表反轉(如何實現鏈表的逆序)

1. 問題:

鏈表 head –>1–>2–>3–>4–>5–>6–>7, 如何反轉為head –>7–>6->5–>4–>3–>2–>1,

2.思路(使用插入法)

思路:從鏈表的第二個節點開始,把遍歷到的節點插入到頭結點的後面,直到遍歷結束。

假設原鏈表:head –>1–>2–>3–>4–>5–>6–>7,

在遍歷2的時候,鏈表變為head –>2–>1–>3–>4–>5–>6–>7,

3.代碼實現:

package LinkedList.Reverse;
/*
 這裡使用插入法進行反轉鏈表
 思路:從鏈表的第二個節點開始,把遍歷到的節點插入到頭結點的後面,直到遍歷結束。
 假設原鏈表:head -->1-->2-->3-->4-->5-->6-->7,
 在遍歷2的時候,鏈表變為head -->2-->1-->3-->4-->5-->6-->7,
 */
public class Reverse {
 public static void main(String[] args) {
  //定義頭結點
  LNode head=new LNode();
  head.next=null;
  LNode temp=null;
  LNode cur=head;
  //構造鏈表
  for (int i = 1; i < 8; i++) {
   temp=new LNode(); //定義一個輔助節點
   temp.data=i;  //temp數據為I
   temp.next=null;
   cur.next=temp; //頭結點的下一個節點為temp
   cur=temp;  //cur後移 由head移動到temp
  }
  System.out.println("逆序前:");
  for (cur=head.next;cur!=null;cur=cur.next){
   System.out.println(cur.data+" ");
  }
  System.out.println("逆序後:");
  Reverse(head);
  for (cur=head.next;cur!=null;cur=cur.next){
   System.out.println(cur.data+" ");
  }
 
 }
 public static void Reverse(LNode head){
  if (head==null || head.next==null){//如果頭結點為空,或者頭結點的下一個節點為空,鏈表不用反轉
   return;
  }
  LNode cur=null;//定義一個當前節點
  LNode next=null;//定義一個後繼節點
  //讓當前節點指向第二個節點
  cur=head.next.next;
  //先把第一個節點設置成最後一個節點
  head.next.next=null;
  while (cur!=null){//如果當前節點不為空
   next=cur.next;//先保存當前節點的後繼節點 如 2 的後面一個節點3 先保存起來
   cur.next=head.next;// 就是把2 的下一個節點指向1
   head.next=cur;//把頭結點指向2
   cur=next; //將當前節點指向下一個 3
  }
 }
}
 
class LNode{
 LNode next;
 int data;
}

使用遞歸法

//使用遞歸法
 private static LNode RecursiveReverse(LNode head){
  //如果鏈表為空或者鏈表隻有一個元素
  if (head==null || head.next==null){
   return head;
  }else {
   //反轉後面的節點
   LNode newHead = RecursiveReverse(head.next);
   //把前面遍歷的節點加到後面節點逆序後鏈表的尾部
   head.next.next=head;
   head.next=null;
   return newHead;
  }
 }
 public static void Reverse(LNode head){
  if (head==null){
   return;
  }
  //獲取鏈表的第一個節點
  LNode firstNode=head.next;
  //對鏈表進行逆序
  LNode newhead = RecursiveReverse(firstNode);
  head.next=newhead;
 
 }

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。如有錯誤或未考慮完全的地方,望不吝賜教。

推薦閱讀: