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。如有錯誤或未考慮完全的地方,望不吝賜教。
推薦閱讀:
- Java實現單鏈表SingleLinkedList增刪改查及反轉 逆序等
- java棧實現二叉樹的非遞歸遍歷的示例代碼
- Java數據結構之鏈表詳解
- java實現簡單單鏈表
- Java二叉樹的四種遍歷方式詳解