棧是數據結構中較為簡單的結構體,是一種操作收到限制的線性表.但簡單不代表沒用,畢竟數組很簡單.但誰敢說數組沒用呢?
棧
棧的理論
- 棧是一個先進后出的結構,類似於堆盤子,先放到地上的盤子最后被取走(默認只能取走一個盤子)
- 棧其實就是操作受限的線性表,只有一個口,每一次操作時,這個口可以當出口也可以當入口.
- 例如:水桶,注入水時,水桶的頭當做入口,倒水時,水桶的頭當做出口
棧的圖解.
在圖解之前,先舉一個例子,讓大家記住棧:
棧其實就是吃了一頓飯,然后吐出來.
- 1. 這是一個空棧,只有上面是入口和出口
- 放入一個元素a
- 放入一個元素b
- 放入一個元素c
- 取出一個元素,由棧只有一個口的特點可以知道取出了C
- 再次放入一個元素d
由圖可以得到:無論是入,還是出,都只有一個口,一個口擔當兩個作用.
棧的可用操作
根據理論環節,可以輕易的看出:棧的基本操作只有兩個:
- 入棧
- 出棧
但是如果棧已經放滿了,就像水桶裝滿了水一樣,不能再放水了,即不能再進行入棧操作,所以要在每次入棧前判斷棧滿的情況.
同理,出棧之前,棧中必須有數據,不然就出現要么空指針,要么野指針.都不是我們想要的結果,所以出棧前要判斷棧空,.
所有一個棧一共有四個功能:
-入棧(英文名:push)
-判(棧)滿(isFull)
-出棧(pop)
-判(棧)空(isEmpty)
棧的C語言定義(結構體)
開篇就說了棧是操作收到限制的線性表,而眾所周知的線性表主要有:
1.順序存儲的數組,
優點: 節省空間, 操作簡單,學習成本較低,易於理解.
缺點: 棧的大小一開始就聲明’死’了,不利於使用.
2.非順序存儲的鏈表.
優缺點:與數組棧正好相反.
- 兩種棧各有好處,爭論是愚蠢的,學習是學不完的,所以趕快開始coding吧
數組棧
- 數組棧,顧名思義,就是基於數組的棧,也是說把一個數組的強大的下標功能閹割掉,並且只能從一頭進入(數組頭明顯更為方便)
所以結構體為:
(為了方便學習,存儲類型統一使用int,但是我們一般更習慣在頭文件下面給int 起一個別名,原因很簡單:這樣就這樣實現簡單的多態,需要將int類型棧改成char類型棧時,只需要改定義的別名中的類型即可)
typedef struct
{
int Data[MaxSize]; // 存儲元素的數組
intTop; //棧頂指針
}SeqStack;
- 棧的四個基本操作定義
//return 0 為false,1為true(下同)
int Push(SeqStack &L)
{
if(L.Top == 0)
{
return 0;
}
printf("%d ",L.Data[--L.Top]);
return 1;
}
int Pop(SeqStack &L, int e)
{
if(L.Top==MaxSize -1)
{
return 0;
}
L.Data[L.Top++] = e;
return 1;
}
//判斷棧s是否為空
int isEmpty(SeqStack s)
{
if(s.Top != 0)
{
return 1;
}
return 0;
}
Status isFull(SeqStack s)
{
if(s.Top != MaxSize -1)//之前的定義數組的最大值的下標
{
return 1;
}
return 0;
}
鏈表棧
結構體
typedef struct LNode
{
ElemType data;
struct LNode * next;
} LNode,*LinkList;
兩大功能(鏈表無需判滿,判空也簡單,不再單獨實現)
Status Push(LinkList L)
{
if(L->next == NULL)
{
return 0;
}
LinkList tem = L->next;
printf("%d ",tem->data);
L->next = tem->next;
free(tem);
return 1;
}
Status Pop(LinkList L, ElemType e)
{
LinkList newNode = (LinkList) malloc(sizeof(LinkList));
newNode->data = e;
newNode->next = L->next;
L->next = newNode;
return 1;
}
最后寫幾個簡單的作業(我們老師留給我們的)以及我的代碼
//1、本題要求實現順序棧,寫出Push 、Pop、StackEmpty函數的實現,並用一個簡單的main函數測試。
//已有類型定義
typedef struct
{
ElementType Data[MaxSize]; // 存儲元素的數組
Position Top; //棧頂指針
}SeqStack;
//函數接口定義:
Status Push(SeqStack &L, ElemType e);
Status Pop(SeqStack &L, ElemType &e);
Status StackEmpty(SeqStack s); //判斷棧s是否為空
//其中 L 和 e 都是用戶傳入的參數。 L 是帶頭結點的頭指針; e 是數據元素。
/** * 3、進制轉換。 * 輸入一個十進制正整數n和一個目標進制R(1<R<10),將n轉換為R進制。要求不使用遞歸或數組,而使用第1題或第2題中定義的棧來實現。 */
代碼:
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 100
typedef int Status;
typedef int ElemType;
typedef int Position;
//1、本題要求實現順序棧,寫出Push 、Pop、StackEmpty函數的實現,並用一個簡單的main函數測試。
//已有類型定義
typedef struct
{
ElemType Data[MaxSize]; // 存儲元素的數組
Position Top; //棧頂指針
} SeqStack;
//函數接口定義:
Status Push(SeqStack &L);
Status Pop(SeqStack &L, ElemType e);
Status StackEmpty(SeqStack s); //判斷棧s是否為空
Status prinStack(SeqStack &L);
Status convNum(int n, int R);
Status pipei();
void work1();
//其中 L 和 e 都是用戶傳入的參數。 L 是帶頭結點的頭指針; e 是數據元素。
int main()
{
//work1();//第一題
//convNum(8,2);//進制轉化
pipei();
return 0;
}
Status prinStack(SeqStack &L)
{
while (StackEmpty(L))
{
Push(L);
}
return 1;
}
void work1()
{
SeqStack L;
L.Top = 0;
Pop(L, 1);
Pop(L, 2);
Pop(L, 3);
prinStack(L);
}
Status Push(SeqStack &L)
{
if(L.Top == 0)
{
return 0;
}
printf("%d ",L.Data[--L.Top]);
return 1;
}
Status Pop(SeqStack &L, ElemType e)
{
if(L.Top==MaxSize -1)
{
return 0;
}
L.Data[L.Top++] = e;
return 1;
}
//判斷棧s是否為空
Status StackEmpty(SeqStack s)
{
if(s.Top != 0)
{
return 1;
}
return 0;
}
//3、進制轉換。
//輸入一個十進制正整數n和一個目標進制R(1<R<10),將n轉換為R進制。要求不使用遞歸或數組,而使用第1題或第2題中定義的棧來實現。
Status convNum(int n, int R)
{
//聲明棧
SeqStack L;
L.Top = 0;
while (n!=0)
{
//將每次產生的余數防入棧低
Pop(L, n%R);
n/=R;
}
prinStack(L);
return 1;
}
以下附上Java 代碼實現的棧
/** * Description: 鏈表實現棧。 * * @ClassName: LinkedStack * @author 過道 * @date 2018年8月10日 下午9:11:30 * @version V1.0 * */
public class LinkedStack<T> implements StackInterface<T> {
private Node topNode;
@Override
public void push(T newEntry) {
Node newNode = new Node<T>(newEntry, topNode);
topNode = newNode;
}
@Override
public T pop() {
T tempData = peek();
if (tempData == null) {
return null;
}
topNode = topNode.next;
return tempData;
}
@Override
public T peek() {
if (isEmpty()) {
return null;
}
return (T) topNode.data;
}
@Override
public boolean isEmpty() {
return topNode == null;
}
@Override
public void clear() {
topNode = null;
// java擁有內存回收,只需要讓頭結點引用為空即可,GC就可以回收掉所有其他節點。
}
public LinkedStack() {
this.topNode = null;
}
private class Node<T> {
private T data;
private Node next;
public Node(T dataPortion) {
this(dataPortion, null);
}
public Node(T data, Node next) {
super();
this.data = data;
this.next = next;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
}