【栈是后进先出的】
先来定义栈的数据结构:
接下来定义栈的一些操作方法:
①、栈的初始化:
#include <stdio.h> struct Link {//栈里面的数据结构由链表来表示 int data; struct Link* next; }; struct Stack { struct Link* head;//栈的头指针 int size;//栈的大小 }; //栈的初始化 void stackInit(struct Stack* stack) { stack->head = NULL; stack->size = 0; } int main(void) { return 0; }
②、往栈中压入一个数据:
关于压栈的整个过程在之前学C时有讲解过,具体可以参考博文:http://www.cnblogs.com/webor2006/p/3481080.html
下面具体实现:
#include <stdio.h> #include <assert.h> #include <malloc.h> struct Link {//栈里面的数据结构由链表来表示 int data; struct Link* next; }; struct Stack { struct Link* head;//栈的头指针 int size;//栈的大小 }; //栈的初始化 void stackInit(struct Stack* stack) { stack->head = NULL; stack->size = 0; } //往栈中压入一个数据 void stackPush(struct Stack* stack, const int data) { //首先产生一个新的结点 struct Link* node; node = (struct Link*)malloc(sizeof(struct Link)); assert(node != NULL); node->data = data; node->next = stack->head; stack->head = node; ++stack->size; } int main(void) { return 0; }
③、往栈中弹出一个数据:
#include <stdio.h> #include <assert.h> #include <malloc.h> struct Link {//栈里面的数据结构由链表来表示 int data; struct Link* next; }; struct Stack { struct Link* head;//栈的头指针 int size;//栈的大小 }; //栈的初始化 void stackInit(struct Stack* stack) { stack->head = NULL; stack->size = 0; } //往栈中压入一个数据 void stackPush(struct Stack* stack, const int data) { //首先产生一个新的结点 struct Link* node; node = (struct Link*)malloc(sizeof(struct Link)); assert(node != NULL); node->data = data; node->next = stack->head; stack->head = node; ++stack->size; } int isStackEmpty(struct Stack* stack) { return (stack->size == 0); } //往栈中弹出一个数据,能出栈返回1,否则返回0 int stackPop(struct Stack* stack, int* data) { if(isStackEmpty(stack)) return 0; struct Link* temp = stack->head; *data = stack->head->data; stack->head = stack->head->next; free(temp); --stack->size; return 1; } int main(void) { return 0; }
④、清除栈:
#include <stdio.h> #include <assert.h> #include <malloc.h> struct Link {//栈里面的数据结构由链表来表示 int data; struct Link* next; }; struct Stack { struct Link* head;//栈的头指针 int size;//栈的大小 }; //栈的初始化 void stackInit(struct Stack* stack) { stack->head = NULL; stack->size = 0; } //往栈中压入一个数据 void stackPush(struct Stack* stack, const int data) { //首先产生一个新的结点 struct Link* node; node = (struct Link*)malloc(sizeof(struct Link)); assert(node != NULL); node->data = data; node->next = stack->head; stack->head = node; ++stack->size; } int isStackEmpty(struct Stack* stack) { return (stack->size == 0); } //往栈中弹出一个数据,能出栈返回1,否则返回0 int stackPop(struct Stack* stack, int* data) { if(isStackEmpty(stack)) return 0; struct Link* temp = stack->head; *data = stack->head->data; stack->head = stack->head->next; free(temp); --stack->size; return 1; } //清除栈 void clearStack(struct Stack* stack) { struct Link* temp; while(stack->head) { temp = stack->head; stack->head = stack->head->next; free(temp); } stack->size = 0; } int main(void) { return 0; }
下面编写测试代码来对其进行测试:
编译运行:
上面用是C的方式来实现的,接下来改用C++的方式,首先声明栈的结构,这里用class来声明:
#include <iostream> using namespace std; class Stack { struct Link {//栈里面的数据结构由链表来表示,这里用结构体来表示是由于默认它里面的成员是公有的,而类默认成员是私有的 int data_; Link* next_; }; private: Link* head_;//栈的头指针 int size_;//栈的大小 }; int main(void) { return 0; }
接着来实现栈的操作函数:
①、栈的初始化:C++中可以在类的构造时进行初始化:
②、往栈中压入一个数据:
#include <iostream> using namespace std; class Stack { struct Link {//栈里面的数据结构由链表来表示,这里用结构体来表示是由于默认它里面的成员是公有的,而类默认成员是私有的 int data_; Link* next_; Link(int data, Link* next):data_(data),next_(next)//结构体实际上就是类,所以也可以构造 { } }; public: Stack(): head_(NULL), size_(0) { } //往栈中压入一个数据 void push(const int data) { //首先产生一个新的结点 Link* node = new Link(data, head_); head_ = node; ++size_; } private: Link* head_;//栈的头指针 int size_;//栈的大小 }; int main(void) { return 0; }
③、往栈中弹出一个数据:
#include <iostream> using namespace std; class Stack { struct Link {//栈里面的数据结构由链表来表示,这里用结构体来表示是由于默认它里面的成员是公有的,而类默认成员是私有的 int data_; Link* next_; Link(int data, Link* next):data_(data),next_(next)//结构体实际上就是类,所以也可以构造 { } }; public: Stack(): head_(NULL), size_(0) { } //往栈中压入一个数据 void push(const int data) { //首先产生一个新的结点 Link* node = new Link(data, head_); head_ = node; ++size_; } //判断栈是否为空栈 bool isStackEmpty() { return (size_ == 0); } //往栈中弹出一个数据,能出栈返回true,否则返回false bool pop(int& data) { if(isStackEmpty()) return false; struct Link* temp = head_; data = head_->data_; head_ = head_->next_; delete temp; --size_; return true; } private: Link* head_;//栈的头指针 int size_;//栈的大小 }; int main(void) { return 0; }
④、清除栈:这个可以放到析构函数中~
#include <iostream> using namespace std; class Stack { struct Link {//栈里面的数据结构由链表来表示,这里用结构体来表示是由于默认它里面的成员是公有的,而类默认成员是私有的 int data_; Link* next_; Link(int data, Link* next):data_(data),next_(next)//结构体实际上就是类,所以也可以构造 { } }; public: Stack(): head_(NULL), size_(0) { } ~Stack() { Link* temp; while(head_) { temp = head_; head_ = head_->next_; delete temp; } } //往栈中压入一个数据 void push(const int data) { //首先产生一个新的结点 Link* node = new Link(data, head_); head_ = node; ++size_; } //判断栈是否为空栈 bool isStackEmpty() { return (size_ == 0); } //往栈中弹出一个数据,能出栈返回true,否则返回false bool pop(int& data) { if(isStackEmpty()) return false; struct Link* temp = head_; data = head_->data_; head_ = head_->next_; delete temp; --size_; return true; } private: Link* head_;//栈的头指针 int size_;//栈的大小 }; int main(void) { return 0; }
接下来进行测试:
编译运行:
对比用C方式实现,有如下不同:
①、栈的初始化放到了构造中,销毁放到了析造当中。
②、每个函数的调用不需要传递栈的地址,调用方式变为了stack.push(),写起来也更加自然一些。
③、用类的方式实现能够避免名称冲突,它的作用域是在类当中所以能有效的避免名称冲突,另外如果真出现还可以用namesapce解决,而用C的方式实现通常方法前面加了一个stack前缀来避免,如:stackPush、stackPop,如果不带前缀可能跟系统库函数的冲突比较大。
④、C++中用类表示栈能达到数据封装性,使得外部不能随意访问里面的私有成员;而C是没有封装性的,外部代码可以任意的修改它里面的数据,如下:
运行就会出错了:
所以可以看出C中存在一定的风险,而C++中的类就可以保护内部的数据结构不遭受破坏。