今天又看了遍《effective C++》,手動實現了一下條款42中的棧,貼出來當博客的處女貼。
首先棧的聲明如下,采用了模板傳入類型,而棧的底層采用是個鏈表。
// stack.h // by Chwen 2014-10-27 #include<stdio.h> #include <stdlib.h> #include <iostream> using namespace std; // 棧聲明 template<typename T> class Stack { public: Stack(); ~Stack(); void push(const T& node); T Top(); void pop(); int size()const; bool Empty() const; void clear(); private: struct StackNode { T data; StackNode* next; StackNode(const T& Newdata, StackNode* nextNode) :data(Newdata),next(nextNode) {} }; StackNode * top; // 防止默認拷貝和默認賦值 Stack(const Stack& rhs); Stack& operator=(const Stack& rhs); int mySize; };
而對應的cpp實現如下:
// stack.cpp #include "stack.h" using namespace std; // 棧實現 template<typename T> Stack<T>::Stack() :top(nullptr),mySize(0) { } template<typename T> Stack<T>::~Stack() { clear(); } template<typename T> void Stack<T>::push(const T& node) { top = new StackNode(node,top); mySize ++; } template<typename T> T Stack<T>::Top() { if (Empty()) { _DEBUG_ERROR("Error, stack is empty!"); } return top->data; } template<typename T> void Stack<T>::pop() { if (Empty()) { _DEBUG_ERROR("Error, stack is empty!"); } StackNode* topOfStack = top; top = top->next; delete topOfStack; topOfStack = nullptr; mySize --; return; } template<typename T> bool Stack<T>::Empty() const { return top == nullptr; } template<typename T> void Stack<T>::clear() { while (top) { StackNode* topOfStack = top; top = top->next; delete topOfStack; } mySize = 0; } template<typename T> int Stack<T>::size()const { return mySize; }
以上即是采用模板實現的棧的所有代碼,可以實現棧的push, pop, top, clear 等操作。
以下寫了一個簡單的測試代碼:
void funv() { Stack<int> s; for(int i = 0; i < 10; ++i) { s.push(i); } for(int j = s.size()-1 ; j >= 0; --j) { cout<< "node: " << s.Top() <<endl; s.pop(); } s.clear(); }
int main ()
{
funv();
getchar();
return 0;
}
之後effective C++指出了另一種更精巧的方式實現,即私有繼承。
代碼實現如下:
// stack.h // by Chwen 2014-10-27 #include<stdio.h> #include <stdlib.h> #include <iostream> class commonStack { protected: commonStack(); ~commonStack(); void push(void* node); void* Top(); void pop(); int size()const; bool Empty() const; void clear(); private: struct StackNode { void* data; StackNode* next; StackNode(void* Newdata, StackNode* nextNode) :data(Newdata),next(nextNode) {} }; StackNode * top; // 防止默認拷貝和默認賦值 commonStack(const commonStack& rhs); commonStack& operator=(const commonStack& rhs); int mySize; }; template <typename T> class Stack:private commonStack { public: void push(T * ty){commonStack::push(static_cast<void*>(ty));} T* top(){return static_cast<T*>(commonStack::Top());} void pop(){return commonStack::pop();} int size(){return commonStack::size();} bool Empty()const{ return commonStack::Empty(); } void clear(){return commonStack::clear();} };
對應的cpp 如下:
#include "stack.h" using namespace std; commonStack::commonStack() :top(nullptr),mySize(0) { } commonStack::~commonStack() { clear(); } void commonStack::push(void* node) { top = new StackNode(node,top); mySize ++; } void* commonStack::Top() { if (Empty()) { _DEBUG_ERROR("Error, stack is empty!"); } return top->data; } void commonStack::pop() { if (Empty()) { _DEBUG_ERROR("Error, stack is empty!"); } StackNode* topOfStack = top; top = top->next; delete topOfStack; topOfStack = nullptr; mySize --; return; } bool commonStack::Empty() const { return top == nullptr; } void commonStack::clear() { while (top) { StackNode* topOfStack = top; top = top->next; delete topOfStack; } mySize = 0; } int commonStack::size()const { return mySize; }
這裡commonStack將原模板類的T改為了void*, 之後使用protected保護該類不會被其他不明群眾調用,而是給出了一個模板接口類私有繼承這個類,這樣一來,既起到了保護作用,又在低損耗的情況下給出了方便易用的接口,巧奪天工的設計。
測試代碼如下:
void funcInt() { int* a[10]; for(int i = 0 ; i < 10; ++i) { a[i] = new int(i); } Stack<int> s; for(int j = 0 ; j < 10; ++j) { s.push(a[j]); } int k = s.size(); int* t = s.top(); s.pop(); if(s.Empty()) { cout<<"empty"<<endl; } s.clear(); for(int i = 0 ; i < 10; ++i) { delete a[i] ; } } void funcString() { string* str[10]; for(int i = 0 ; i < 10; ++i) { str[i] = new string("a"); } Stack<string> s; for(int j = 0 ; j < 10; ++j) { s.push(str[j]); } int k = s.size(); string* t = s.top(); s.pop(); if(s.Empty()) { cout<<"empty"<<endl; } s.clear(); for(int i = 0 ; i < 10; ++i) { delete str[i] ; } } int main () { funcInt(); funcString(); getchar(); return 0; }
測試代碼沒有輸出,可以斷點看數據。
之後我又去看了一眼STL對棧的實現,它默認使用deque作為棧的底層實現。
template<class _Ty, class _Container = deque<_Ty> > class stack { // 棧實現 }
調用的時候直接std::stack<int> 即默認使用deque作為棧底層容器。
用戶也可以指定其他方式,比如std::stack<int, std::list<int> >, 這樣就使用了list作為棧的底層容器。
讓我感到awesome的是STL實現的精巧和靈活性,居然是可指定底層的一種實現方法,太精巧了。回頭再去看一下《STL源碼剖析》。
只羅列了代碼,沒太詳細的介紹原理,感興趣的可以直接去看《effective C++》和《STL源碼剖析》,以及STL的stack代碼。
引用請注明出處,http://www.cnblogs.com/chwen/p/4055474.html 非常感謝,隨時交流。
#include<stdio.h>
#include<stdlib.h>
/*定義常量*/
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define null 0
#define INFEASIBLE -1
#define OVERFLOW -2
/*定義棧初始分配空間及增量*/
#define initSize 100
#define increment 10
typedef int SElemType;
typedef int Status;
/*定義順序棧類型*/
typedef struct Stack{
SElemType *base;/*棧構造前和銷毀後棧底base為null*/
SElemType *top;/*棧頂指針*/
int stackSize;/*以元素為單位分配當前存儲空間*/
}Stack;
Status initStack(Stack *S){/*初始化一個空棧並將其返回*/
(*S).base=(SElemType *)malloc(initSize*sizeof(SElemType));
if(!(*S).base) exit(OVERFLOW);
(*S).top=(*S).base;
(*S).stackSize=initSize;
return OK;
}
Status destroyStack(Stack *S){/*銷毀棧*/
free((*S).base);
(*S).base=NULL;
(*S).top=NULL;
(*S).stackSize=0;
return OK;
}
Status clearStack(Stack *S){/*清空棧*/
(*S).top=(*S).base;
return OK;
}
Status stackEmpty(Stack S){/*判斷棧是否為空*/
return (S.top==S.base);
}
int stackLength(Stack S){ /*用return返回站棧的長度*/
return S.top-S.base;
}
/**************/
Status getTop(Stack S,SElemType *e){
/*用*e以返回棧頂元素至e */
if(S.top>S.base){
*e=*(S.top-1);
return OK;
}
else return ERROR;
}
Status push(Stack *S,SElemType e){
/*將e入棧以成為新棧頂,並將棧返回*/
if((*S).top-(*S).base>=(*S).stackSize){
/*棧滿,追加空間*/
(*S).base=(SElemType *)realloc((*S).base,((*S).stackSize+increment)*sizeof(SElemType));
if(!(*S).base) exi......余下全文>>
不得不說,我還沒有用過呢。你可以看看“c語言如何實現函數模板”,這個應該會對你有所幫助的。這個在c++中特別容易實現,但是c語言因為沒有函數模板,故而需要自己構造,一般都是宏的策略或者函數指針,不過我還沒有碰到過。