数据结构随笔——栈,及STL中的<stack>

一、栈的定义

在我们软件应用中,栈这种后进先出数据结构的应用是非常普遍的。比如你用浏览器上网时,不管什么浏览器都有一一个“后退”键,你点击后可以按访问顺序的逆序加载浏览过的网页。这就是栈的一个实际运用。

栈(stack)是仅限在表尾进行插入和删除的线性表

二、栈的顺序存储结构及代码实现

首先来看,栈的定义,这里是用数组实现栈,实际上用链表也可以实现,称为链式栈。

个人认为栈这部分重点在于看懂源码,动手实现起来是十分容易的。

#define datatype int 
#define maxsize 1024
struct stack
{
	datatype data[maxsize];
	int top; //栈顶指针,1个元素就是0,2个就是1,以此类推
};

栈的初始化

首先要对这个结构体申请空间,然后传回该结构体的指针。

stack* init_stack() //返回类型为结构体指针的函数,初始化栈
{
	stack* s;
	s = (stack*)malloc(sizeof(stack));
	if (!s)
	{
		cout << "空间不足,申请失败" << endl;
		return NULL;
	}
	else 
	{
		s->top = -1;//定义栈底为-1
		return s;
	}
}

入栈

要判断是否为栈满,然后将该元素压入。

int push(stack* s, datatype x) //入栈
{
	if (s->top == maxsize - 1)
	{
		cout << "栈满,无法入栈" << endl;
		return 0;
	}
	else
	{
		s->data[++s->top] = x;
		return 1;
	}
}

出栈

要判断是否为空栈,然后将该元素的值传给指针。(改变函数,返回该值也可以)。

int pop(stack* s, datatype* e) //出栈一个元素,并且用e返回其值
{
	if (empty_stack(s))
	{
		cout << "栈空,无法出栈" << endl;
		return 0;
	}
	else
	{
		*e = s->data[s->top--];
		return 1;
	}
}

判断空栈

这个很简单,看top值是否为-1即可。

int empty_stack(stack* s) //判断空栈
{
	if (s->top == -1)
		return 1; //为空
	else
		return 0;
}

获得栈顶元素

datatype gettop(stack* s)
{
	if (empty_stack(s))
	{
		cout << "栈空,无栈顶元素" << endl;
		return 0;
	}
	else
		return s->data[s->top]; //返回栈顶
}

显示栈中所有元素,自上而下

void print_stack(stack* s) //显示所有元素
{
	if (empty_stack(s))
	{
		cout << "栈空,无元素" << endl;
		return;
	}
	else
	{
		for (int i = s->top; i >= 0; i--)
			cout << s->data[i] << endl;
		return;
	}
}

至于返回栈中元素数量,这个可以定义一个函数返回top+1的值,即为元素个数。同理,删除这个栈中所有元素,只需要把top的值修改为-1即可。销毁栈,释放栈空间即可。在此不多赘述。

三、STL中的<stack>

这就十分简单了,函数都封装好了。C++中stl的stack(栈)以其他容器(deque默认,vector,list)作为底层数据结构而形成,只是修改了接口以满足栈的特性。

#include<stack>//栈
stack<int>  s;//参数也是数据类型,这是栈的定义方式
s.empty()//如果栈为空返回true,否则返回false  
s.size()//返回栈中元素的个数  
s.pop()//删除栈顶元素但不返回其值  
s.top()//返回栈顶的元素,但不删除该元素  
s.push(X)//在栈顶压入新元素 ,参数X为要压入的元素

四、两栈共享空间

数组有两个端点,两个栈有两个栈底,让一个栈的栈底为0,另一个为栈的栈末端,即为数组大小的n-1处。这样,两个栈都增加元素都是往中间处靠拢。

在这里插入图片描述

栈1为空时,就是top1等于-1时,而当top2等于n时,即是栈2为空时,那什么时候栈满呢?

若栈2是空栈,栈1的top1等于n-1时,就是栈1满了。反之,当栈1为空栈时,top2 等于0时,为栈2满。但更多的情况,其实就是,两个指针之间相差1时,即top1 + 1 == top2 为栈满。

事实上,使用这样的数据结构,通常都是当两个栈的空间需求有相反关系时,也就是一个栈增长时另一个栈在缩短的情况。当然,这只是针对两个具有相同数据类型的栈的一一个设计上的技巧,如果是不相同数据类型的栈,这种办法不但不能更好地处理问题,反而会使问题变得更复杂。

定义

#define datatype int 
#define maxsize 1024
typedef struct
{
  datatype data[maxsize];
	int top1;
	int top2;
}doublestack;

压入元素

在压入和删除时,就只是需要判断一下对哪个栈操作而已。

int double_stack_push(doublestack* s, int stacknumber, datatype x) 
//结构体指针,要操作的栈,要压入的元素
{
	if (s->top1 + 1 == s->top2)
		return 0; //栈满
	else
	{
		if (stacknumber == 1)
			s->data[++s->top1] = x; //先自加再赋值
		else if(stacknumber==2)
			s->data[--s->top2] = x;
		return 1;
	}
}

删除元素

int double_stack_pop(doublestack* s, int stacknumber,datatype* e)
{
	if (stacknumber == 1)
	{
		if (s->top1 == -1)
			return 0; //栈1为空
		else
			*e = s->data[s->top1--];//先出栈再自减
	}
	else if (stacknumber == 2)
	{
		if (s->top1 == maxsize)
			return 0; //栈1为空
		else
			*e = s->data[s->top2++];//先出栈再自加
	}
	return 1;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是手动实现这些头文件里所有的STL容器的代码: ``` // iostream namespace mystd { class ostream { public: ostream& operator<<(const char* str) { // 实现输出字符串的逻辑 return *this; } // 其他重载运算符和成员函数 }; static ostream cout; } // memory namespace mystd { template<typename T> class allocator { public: using value_type = T; // 实现分配和释放内存的函数 }; } // stack namespace mystd { template<typename T, typename Container = mystd::vector<T>> class stack { public: using value_type = T; using container_type = Container; // 实现的各种函数 }; } // fstream namespace mystd { class filebuf { public: // 实现文件缓冲区相关函数 }; class ifstream { public: ifstream(const char* filename) { // 实现打开文件的逻辑 } // 实现读取文件的逻辑 }; class ofstream { public: ofstream(const char* filename) { // 实现打开文件的逻辑 } // 实现写入文件的逻辑 }; } // vector namespace mystd { template<typename T, typename Allocator = mystd::allocator<T>> class vector { public: using value_type = T; using allocator_type = Allocator; // 实现vector的各种函数 }; } // cmath namespace mystd { double pow(double base, double exponent) { // 实现求幂函数 } // 其他数学函数的实现 } // iomanip namespace mystd { class setprecision { public: setprecision(int n) { // 实现设置输出精度的逻辑 } // 其他重载运算符和成员函数 }; } // exception namespace mystd { class exception { public: virtual const char* what() const noexcept { return "Unknown exception"; } }; } // climits namespace mystd { constexpr int INT_MAX = 2147483647; // 其他常量的定义 } // array namespace mystd { template<typename T, std::size_t N> class array { public: using value_type = T; // 实现数组的各种函数 }; } // cstdint namespace mystd { using int8_t = signed char; using int16_t = short int; using int32_t = int; using int64_t = long long int; // 其他数据类型的定义 } // string namespace mystd { class string { public: // 实现字符串的各种函数 }; } ``` 以上代码只是简单实现了各个STL容器的基本功能,具体实现方式和函数可能会有所不同,仅供参考。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值