C++ 堆棧 stack

[TOP]


    ~~~~棧和隊列是兩種重要的線性結構,是很常用的數據結構。從數據結構的角度看,棧和隊列也是線性結構,其特殊性在於棧和隊列的基本操作是線性表操作的子集,它們是操作受限的線性表,因此,可稱爲限定性的數據結構。但是從數據類型角度看,它們是和線性表大不相同的兩類重要的抽象數據類型。由於它們廣泛應用在各種軟件系統中,因此在面向對象的程序設計中,它們是多型數據類型。
這裏我們只學習堆棧。

堆棧


介紹

  • 堆棧(英語:stack)又稱爲棧或堆疊,是計算機科學中的一種抽象數據類型,只允許在有序的線性數據集合的一端(稱爲堆棧頂端,英語:top)進行加入數據(英語:push)和移除數據(英語:pop)的運算。因而按照後進先出(LIFO, Last In First Out)的原理運作。

常與另一種有序的線性數據集合隊列相提並論,堆棧常用一維數組或鏈表來實現。

操作

堆棧使用兩種基本操作:推入(壓棧,push)和彈出(彈棧,pop):

  • 推入:將數據放入堆棧頂端,堆棧頂端移到新放入的數據。
  • 彈出:將堆棧頂端數據移除,堆棧頂端移到移除後的下一筆數據。

特點

堆棧的基本特點:

  • 先入後出,後入先出。
  • 除頭尾節點之外,每個元素有一個前驅,一個後繼。

實現

堆棧實現一共有兩種方法,一種是數組,一種是鏈表,本來打算自己寫一個,後來考慮,我們應該先學習現有的,於是我去std裏面找stack,我們可以先看一看std的源碼。

  template<typename _Tp, typename _Sequence = deque<_Tp> >
    class stack
    {
      // concept requirements
      typedef typename _Sequence::value_type _Sequence_value_type;
      __glibcxx_class_requires(_Tp, _SGIAssignableConcept)
      __glibcxx_class_requires(_Sequence, _BackInsertionSequenceConcept)
      __glibcxx_class_requires2(_Tp, _Sequence_value_type, _SameTypeConcept)

      template<typename _Tp1, typename _Seq1>
        friend bool
        operator==(const stack<_Tp1, _Seq1>&, const stack<_Tp1, _Seq1>&);

      template<typename _Tp1, typename _Seq1>
        friend bool
        operator<(const stack<_Tp1, _Seq1>&, const stack<_Tp1, _Seq1>&);

    public:
      typedef typename _Sequence::value_type                value_type;
      typedef typename _Sequence::reference                 reference;
      typedef typename _Sequence::const_reference           const_reference;
      typedef typename _Sequence::size_type                 size_type;
      typedef          _Sequence                            container_type;

    protected:
      //  See queue::c for notes on this name.
      _Sequence c;

    ~~~~可以很明顯的發現,stl裏面的用的是一個deque的一個東西進行內部內存管理,而deque是一個雙端隊列。
    ~~~~雙端隊列(deque,全名double-ended queue)是一種具有隊列和棧性質的抽象數據類型。雙端隊列中的元素可以從兩端彈出,插入和刪除操作限定在隊列的兩邊進行。是不是很像雙向鏈表。
    ~~~~我們可以發現stack默認是使用deque的,但是其實也是可以使用其他的容器,只要對應的容器滿足一定的條件就可以了,這其實就是一個分匹配器。
    ~~~~下面就是一個C語言的stack,有兩種實現的方法,一種是數組堆棧,一種的串列堆棧,下面的是串列堆棧。

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

#define elemType int							/* 鏈棧元素數據類型,以整型爲例 */
#define SNODE_SIZE sizeof (struct sNode)		/* 鏈棧結點空間大小 */

#define status int	/* 狀態型變量 */
#define OVERFLOW -1	/* 內存溢出狀態碼 */
#define ERROR 0		/* 錯誤狀態碼 */
#define OK 1		/* 正確狀態碼 */

/* 鏈棧結點存儲結構 */
typedef struct sNode {
	elemType data;
	struct sNode *next;
} sNode, *sNodePtr;

/* 鏈棧存儲結構 */
typedef struct linkStack {
	sNodePtr top; /* 棧頂指針 */
} linkStack;

/* 初始化 */
/* 操作結果:構造一個帶頭結點的空鏈棧S */
void initStack (linkStack *S) {
	S->top = (sNodePtr) malloc (SNODE_SIZE); /* 產生頭結點,棧頂指針指向此頭結點 */
	if (!S->top) /* 內存分配失敗 */
		exit (OVERFLOW);
	S->top->next = NULL;
}

/* 銷燬 */
/* 初始條件:鏈棧S已存在。操作結果:銷燬鏈棧S */
void destroyStack (linkStack *S) {
	sNodePtr p, q;
	
	p = S->top; /* p指向S的頭結點 */
	while (p) {
		q = p->next; /* q指向p的下一個結點 */
		free (p); /* 回收p指向的結點 */
		p = q; /* p移動到下一個結點 */
	} /* 直到沒有下一個結點 */
}

/* 清空 */
/* 初始條件:鏈棧S已存在。操作結果:將S重置爲空棧 */
void clearStack (linkStack *S) {
	sNodePtr p, q;
	
	p = S->top->next; /* p指向棧的第一個結點 */
	while (p) {
		q = p->next; /* q指向p的下一個結點 */
		free (p); /* 回收p指向的結點 */
		p = q; /* p移動到下一個結點 */
	}  /* 直到沒有下一個結點 */
	
	S->top->next = NULL;
}

/* 判斷鏈棧是否爲空 */
/* 初始條件:鏈棧S已存在。操作結果:若S爲空鏈棧,則返回TRUE,否則返回FALSE */
status stackIsEmpty (linkStack *S) {
	return S->top->next == NULL;
}

/* 求鏈棧長度 */
/* 初始條件:鏈棧S已存在。操作結果:返回S中數據元素個數 */
int stackLength (linkStack *S) {
    int i = 0;
    sNodePtr p;
	
	p = S->top->next; /* p指向棧的第一個結點 */
	while (p) { /* 未到棧尾 */
		i++;
		p = p->next;
    }
    
    return i;
}

/* 獲取棧頂元素 */
/* 初始條件:鏈棧S已存在。操作結果:當棧不爲空時,將棧頂元素其值賦給e並返回OK,否則返回ERROR */
status getTopElem (linkStack *S, elemType *e) {
	sNodePtr p;
	
	if (stackIsEmpty (S))
		return ERROR;
	
	p = S->top->next; /* p指向棧的第一個結點 */
	*e = p->data;
	
	return OK;
}

/* 入棧 */
/* 操作結果:在S的棧頂插入新的元素e */
status push (linkStack *S, elemType e) {
	sNodePtr p;
	
	p = (sNodePtr) malloc (SNODE_SIZE); /* 產生新結點 */
	if (!p) /* 內存分配失敗 */
		exit (OVERFLOW);
	
	p->data = e;
	p->next = S->top->next; /* 將新結點鏈接到原棧頂 */
	S->top->next = p; /* 棧頂指向新結點 */
}

/* 出棧 */
/* 操作結果:刪除S的棧頂元素,並由e返回其值 */
status pop (linkStack *S, elemType *e) {
	sNodePtr p;
	
	if (stackIsEmpty (S))
		return ERROR;
	
	p = S->top->next; /* p指向鏈棧的第一個結點 */
	*e = p->data; /* 取出數據 */
	S->top->next = p->next;
	free (p); /* 刪除該結點 */
	
    if (S->top == p) /* 棧爲空 */
    	S->top->next = NULL;
    
    return OK;
}

/* 打印棧內容 */
/* 初始條件:鏈棧S已存在。操作結果:當棧不爲空時,打印棧內容並返回OK,否則返回ERROR */
status printStack (linkStack *S) {
	sNodePtr p;
	
	if (stackIsEmpty (S))
		return ERROR;
	
	p = S->top->next;
	while (p) {
		printf ("%d\t", p->data);
		p = p->next;
	}
	putchar ('\n');
	
	return OK;
}

我們實際使用還是會使用std::stack就可以了,當然我們也可以根據自身的要求重寫stack裏面默認的deque,來優化內存管理。
std::stack的調用還是很簡單的:

#include <iostream>
#include <stack>


int main(){
    std::stack<int> _t_stack;
    
    for(int i = 0; i < 10; i++){
        _t_stack.push(i);
        std::cout << "push data:" << i << std::endl;
    }

    while(!_t_stack.empty()){
        std::cout << "top data:" << _t_stack.top() << std::endl;
        _t_stack.pop();
    }
    return 1;
}

這是直接在windows上編譯了:

PS F:\C++\studytest\structure\test1> g++ -o test .\stack_test.cpp
PS F:\C++\studytest\structure\test1> .\test.exe
push data:0
push data:1
push data:2
push data:3
push data:4
push data:5
push data:6
push data:7
push data:8
push data:9
top data:9
top data:8
top data:7
top data:6
top data:5
top data:4
top data:3
top data:2
top data:1
top data:0
PS F:\C++\studytest\structure\test1>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章