數據結構與算法-棧和隊列

一、基本含義

參考:https://mp.weixin.qq.com/s/D9_wM42c3Czhg9-NsPFJ8Q
鏈表和數組是線性結構的基礎,棧和隊列是線性結構的應用。

1.1 棧

含義:可以將棧看成一個箱子。
作用:放置數據。
分類:靜態棧(數組實現) + 動態棧(鏈表實現)。
在這裏插入圖片描述

項目 含義
入棧 往箱子裏面放東西
出棧 往箱子裏面取東西
棧底 箱子的底部
棧頂 箱子的頂部
特性 先進後出(LIFO, Last In First Out)

1.2 隊列

含義:可以將隊列看成小朋友排隊。
作用:放置數據。
分類:靜態隊列(數組實現) + 動態隊列(鏈表實現)。
在這裏插入圖片描述

項目 含義
入隊 新的小朋友排隊打飯了
出隊 小朋友打完飯,走了。
隊頭 第一個小朋友
對尾 最後一個小朋友
特性 先進先出

二、代碼實現

2.1 棧

2.1.1 創建節點類與棧類

本處採用鏈表創建動態棧。
Node.java

public class Node {    
    public int data;//數據域    
    public Node next;//指針域,指向下一個節點
    public Node() {
    }
    public Node(int data) {
        this.data = data;
    }
    public Node(int data, Node next) {
        this.data = data;
        this.next = next;
    }
}

Stack.java

public class Stack {
    public Node stackTop; // 棧頂指針
    public Node stackBottom; // 棧底指針
    public Stack(Node stackTop, Node stackBottom) {
        this.stackTop = stackTop;
        this.stackBottom = stackBottom;
    }
    public Stack() {
    }
}

2.1.2 遍歷棧

含義:獲取節點值。
只要棧頂元素的指針不指向棧底,那麼就一直輸出遍歷結果。

public static void traverse(Stack stack) {
	Node stackTop = stack.stackTop;
	while (stackTop != stack.stackBottom) {
		System.out.println("棧元素值:" + stackTop.data);
		stackTop = stackTop.next;
	}
}

2.1.3 判斷該棧是否爲空

含義:是否有元素。
只要棧頂和棧底是同一指向,那麼該棧就爲空。

public static boolean isEmpty(Stack stack) {
	return ((stack.stackTop == stack.stackBottom) ? true:false);
}

2.1.4 入棧(進棧)

含義:增加新節點。
將原本棧頂指向的節點交由新節點來指向,棧頂指向新加入的節點。

public static void pushStack(Stack stack, int value) {
	Node newNode = new Node(value); // 新節點
	// 交換。
	newNode.next = stack.stackTop;// 棧頂本來指向的節點交由新節點來指向	
	stack.stackTop = newNode;// 棧頂指針指向新節點
}

2.1.5 出棧

含義:刪除元素。
1、在出棧之前看看該棧是否爲空,不爲空纔出棧…
2、將棧頂的元素的指針(指向下一個節點)賦值給棧頂指針(完成出棧)

public static void popStack(Stack stack) {
	// 棧不爲空才能出棧
	if (!isEmpty(stack)) {		
		Node top = stack.stackTop;//棧頂元素		
		stack.stackTop = top.next; // 棧頂指針指向下一個節點
		System.out.println("出棧的元素是:" + top.data);
	}
}

2.1.6 清空棧

含義:刪除所有元素。
棧頂指向棧底,就清空棧了。

public static void clearStack(Stack stack) {
	stack.stackTop = null; // 棧頂置空
	stack.stackBottom = stack.stackTop; // 棧底指向棧頂。
}

2.2 隊列

使用數組來實現靜態隊列,往往實現靜態隊列,我們都是做成循環隊列。
做成循環隊列的好處是不浪費內存資源!
在這裏插入圖片描述
注意:
1、初始值,front = 0,rear = 0;
2、非循環隊列時:入隊時,rear++。出隊時,front++。
3、數組長度 >= 隊列長度 + 1
4、循環隊列時:入隊時,(rear+1)% arr.length。出隊時,(front + 1) % arr.length。

2.2.1 創建隊列類

Queue.java

public class Queue {    
    public int [] arrays; // 數組    
    public int front; // 指向第一個有效的元素    
    public int rear; // 指向有效數據的下一個元素(即指向無效的數據)
}
// rear並不指向最後一個有效的元素。目的:讓我們分得清隊頭和隊尾。

2.2.2 初始化隊列

此時隊列爲空,分配了6個長度給數組(只能裝5個實際的數字,rear指向的是無效的位置的)

public static void main(String[] args) {
	//初始化隊列
	Queue queue = new Queue();
	queue.front = 0;
	queue.rear = 0;
	queue.arrays = new int[6];
}
// 注意:此處數組長度雖然爲6,但只能裝5個實際數字。
// 注意:一般情況下,隊列的長度 != 數組的長度。滿員時,隊列的長度 + 1 = 數組的長度。原因rear指向的是無效的位置的。

2.2.3 遍歷

只要front節點不指向rear節點,那麼就可以一直輸出

public static void traverseQueue(Queue queue) {	
	int i = queue.front;// front的位置
	while (i != queue.rear) {
		System.out.println("元素的值" + queue.arrays[i]);		
		i = (i + 1) % queue.arrays.length;//移動front
	}
}

2.2.4 判斷

隊列滿員狀態:如果rear指針和front指針緊挨着,那麼說明隊列就滿了。
隊列爲空狀態:只要rear和front指針指向同一個位置,那該隊列就是空的了

// 隊列是否滿了。
public static boolean isFull(Queue queue) {
	boolean result = ((queue.rear + 1) % queue.arrays.length == queue.front)? true:false;
	return result;
}
// 隊列是否爲空
public static boolean isEmpty(Queue queue) {
	return (queue.rear  == queue.front) ? true:false;
}

2.2.4 入隊

1、判斷該隊列是否滿了。
2、入隊的值插入到隊尾中(具體的位置就是rear指針的位置)。
3、rear指針移動,再次指向無效的元素位置。

public static void enQueue(Queue queue,int value) {
	// 不是滿的隊列才能入隊
	if (!isFull(queue)) {
		// 將新的元素插入到隊尾中
		queue.arrays[queue.rear] = value;
		// rear節點移動到新的無效元素位置上
		queue.rear = (queue.rear + 1) % queue.arrays.length;
	}
}

2.2.6 出隊

1、判斷該隊列是否爲null
2、如果不爲null,則出隊,只要front指針往後面移就是出隊了!

public static void outQueue(Queue queue) {
	if (!isEmpty(queue)) {
		int value = queue.arrays[queue.front];
		System.out.println("出隊的元素是:" + value);
		// front指針往後面移
		queue.front = (queue.front + 1) % queue.arrays.length;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章