栈(Stack)的原理与代码实现

这篇具有很好参考价值的文章主要介绍了栈(Stack)的原理与代码实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

栈(stack)

原理说明:

​ 学习数据结构的目的是为了更好的处理和存储数据,对于顺序表而言改查比较容易,增删比较麻烦,对于链式表而言,增删比较简单,改查比较麻烦,所以每种数据结构都有不同的特点,用户需要选择合适的数据结构。

​ 栈内存自顶向下进行递增,其实栈和顺序表以及链式表都一样,都属于线性结构,****存储的数据的逻辑关系也是一对一的。

栈(Stack)的原理与代码实现

​ 如上图所示,栈的模型类似一一个瓶子。

​ 1)栈的一端是封闭的,数据的插入与删除只能在栈的另一端进行,也就是栈遵循“*后进先出*”的原则。也被成为“LIFO”结构,意思是“last input first output”。

​ 2)栈(stack),存储货物或供旅客住宿的地方,可引申为仓库、中转站,所以引入到计算机领域里,就是指数据暂时存储的地方,所以才有进栈(PUSH)、出栈(POP)的说法。

栈原理举例

栈(Stack)的原理与代码实现

​ 如图所示,在三本书均放进“栈”中后,我们想要取得Blue书时,必须将前两本书依次取出,即是栈“先进后出”特点的展示。

​ 闭合的一端被称为栈底(Stack Bottom),允许数据的插入与删除的一端被称为栈顶(Stack Top),不包含任何元素的栈被称为空栈。

  • 把数据插入到栈空间的动作被称为入栈或者压栈(push)

栈(Stack)的原理与代码实现

  • 从栈空间中删除数据的动作被称为出栈或者弹栈(pop)

栈(Stack)的原理与代码实现

代码实现

​ 由于栈也是一种线性结构,所以可以以数组或者链表作为基础,在此基础上实现栈的操作。

顺序栈:以数组作为基础实现栈空间

​ 数组在内存中占用一块连续的空间,也就是数组元素的内存地址是连续的。为了实现栈,一般是把数组头作为栈底,数组头部到数组尾部作为栈的增长方向,也就是用户只在数组尾部对数据进行插入和删除。这样规定的原因其一是因为数组能够进行随机访问,所以数组的尾插较为便利。

栈(Stack)的原理与代码实现

代码实现:

​ 为了方便管理顺序栈所以需要构造管理顺序栈信息的结构体类型,用于记录重要参数,如下:

//指的是顺序栈中的元素的数据类型,用户可以根据需要进行修改
typedef int  DataType_t;

//构造记录顺序栈SequenceStack各项参数(栈底地址+栈容量+栈顶元素的下标)的结构体
typedef struct SequenceStack
{
	DataType_t * Bottom;		//记录栈底地址
	unsigned int Size;			//记录栈容量
	int			 Top;      		//记录栈顶元素的下标	

}SeqStack_t;

  1. 创建一个空的顺序栈,并为记录顺序栈信息的结构体申请堆内存,并进行初始化即可

    /*********************************************************************
    *
    *	name	 :	SeqStack_Create
    *	function :  创建一个空的顺序栈,并为记录顺序栈信息的结构体
    				申请堆内存,并进行初始化即可!
    *	argument :  
    *				@size  :栈的容量大小
    *				
    *	retval	 :  调用成功返回顺序栈的地址
    *	author	 :  790557054@qq.com
    *	date	 :  2024/04/25
    * 	note	 :  none
    * 	
    * *****************************************************************/
    //创建顺序表并对顺序栈进行初始化
    SeqStack_t * SeqStack_Create(unsigned int size)
    {
    	//1.利用calloc为顺序栈的管理结构体申请一块堆内存
    	SeqStack_t *Manager = (SeqStack_t *)calloc(1,sizeof(SeqStack_t));
    
    	if(NULL == Manager)
    	{
    		perror("calloc memory for manager is failed");
    		exit(-1); //程序异常终止
    	}
    
    	//2.利用calloc为所有元素申请堆内存
    	Manager->Bottom = (DataType_t *)calloc(size,sizeof(DataType_t));
    
    	if (NULL == Manager->Bottom)
    	{
    		perror("calloc memory for Stack is failed");
    		free(Manager);
    		exit(-1); //程序异常终止
    	}
    
    	//3.对管理顺序栈的结构体进行初始化(元素容量 + 最后元素下标)
    	Manager->Size = size;	//对顺序栈中的容量进行初始化
    	Manager->Top = -1;		//由于顺序栈为空,则栈顶元素的下标初值为-1
    	
    	return Manager;
    }
    
  2. 根据栈的特性,把新元素从栈顶入栈,也就是从数组的尾部进行元素插入,操作如下:

    /*********************************************************************
    *
    *	name	 :	SeqStack_IsFull
    *	function : 判断顺序栈是否已满
    *	argument :  
    *				@Manager  :顺序栈的地址
    *				
    *	retval	 :  调用成功返回bool型,满了则返回true,没满返回false
    *	author	 :  790557054@qq.com
    *	date	 :  2024/04/25
    * 	note	 :  none
    * 	
    * *****************************************************************/
    bool SeqStack_IsFull(SeqStack_t *Manager)
    {
    	return (Manager->Top + 1 == Manager->Size) ? true : false;
    }
    /*********************************************************************
    *
    *	name	 :	SeqStack_Push
    *	function : 根据栈的特性,把新元素从栈顶入栈,也就是从数组的尾部进行元素插入
    *	argument :  
    *				@Manager  :顺序栈的地址
    				@Date  	  :要入栈的数据
    *				
    *	retval	 :  调用成功返回bool型,满了则返回true,没满返回false
    *	author	 :  790557054@qq.com
    *	date	 :  2024/04/25
    * 	note	 :  none
    * 	
    * *****************************************************************/
    //入栈
    bool SeqStack_Push(SeqStack_t *Manager, DataType_t Data)
    {
    	//1.判断顺序栈是否已满
    	if ( SeqStack_IsFull(Manager) )
    	{
    		printf("SeqStack Full is Full!\n");
    		return false;
    	}
    
    	//2.如果顺序栈有空闲空间,则把新元素添加到顺序栈的栈顶
    	Manager->Bottom[++Manager->Top] = Data;
    
    	return true;
    }
    
    
  3. 根据栈的特性,把元素从栈顶出栈,也就是把元素从数组的尾部把元素删除

    /*********************************************************************
    *
    *	name	 :	SeqStack_IsEmpty
    *	function : 	判断顺序栈是否为空
    *	argument :  
    *				@Manager  :顺序栈的地址
    *				
    *	retval	 :  调用成功返回bool型,空了则返回true,没空返回false
    *	author	 :  790557054@qq.com
    *	date	 :  2024/04/25
    * 	note	 :  none
    * 	
    * *****************************************************************/
    bool SeqStack_IsEmpty(SeqStack_t *Manager)
    {
    	return (-1 == Manager->Top) ? true : false;
    }
    /*********************************************************************
    *
    *	name	 :	SeqStack_Pop
    *	function : 根据栈的特性,把元素从栈顶出栈,也就是把元素从数组的尾部把元素删除
    *	argument :  
    *				@Manager  :顺序栈的地址
    *				
    *	retval	 :  调用成功返回新的栈地址
    *	author	 :  790557054@qq.com
    *	date	 :  2024/04/25
    * 	note	 :  none
    * 	
    * *****************************************************************/
    //出栈
    DataType_t SeqStack_Pop(SeqStack_t *Manager)
    {
    	DataType_t temp = 0;  //用于存储出栈元素的值
    
    	//1.判断顺序栈是否为空
    	if ( SeqStack_IsEmpty(Manager) )
    	{
    		printf("SeqStack is Empty!\n");
    		return;
    	}
    	
    	//2.由于删除了一个元素,则需要让顺序栈的栈顶元素下标-1
    	temp = Manager->Bottom[Manager->Top--];
    
    	return temp;
    }
    
  4. 对顺序栈中的元素进行遍历,只需要从顺序栈的栈底开始向栈顶进行遍历

    //遍历顺序表的元素
    void SeqStack_Print(SeqStack_t *Manager)
    {
    	for (int i = 0; i <= Manager->Top; ++i)
    	{
    		printf(" Stack Element[%d] = %d\n",i,Manager->Bottom[i]);
    	}
    }
    

    代码完整展示

    /*******************************************************************
    *
    *	file name:	SequenceStack.c
    *	author	 :  790557054@qq.com
    *	date	 :  2024/04/25
    *	function :  该案例是以数组作为基础实现栈空间,并且把数组头作为栈底,
    				数据头部到数据尾部作为栈的增长方向。
    * 	note	 :  None
    *
    *	CopyRight (c)  2023-2024   790557054@qq.com   All Right Reseverd 
    *
    * *****************************************************************/
    #include <stdio.h>
    #include <stdbool.h>
    #include <stdlib.h>
    
    //指的是顺序栈中的元素的数据类型,用户可以根据需要进行修改
    typedef int  DataType_t;
    
    //构造记录顺序栈SequenceStack各项参数(栈底地址+栈容量+栈顶元素的下标)的结构体
    typedef struct SequenceStack
    {
    	DataType_t * Bottom;		//记录栈底地址
    	unsigned int Size;			//记录栈容量
    	int			 Top;      		//记录栈顶元素的下标	
    
    }SeqStack_t;
    /*********************************************************************
    *
    *	name	 :	SeqStack_Create
    *	function :  创建一个空的顺序栈,并为记录顺序栈信息的结构体
    				申请堆内存,并进行初始化即可!
    *	argument :  
    *				@size  :栈的容量大小
    *				
    *	retval	 :  调用成功返回顺序栈的地址
    *	author	 :  790557054@qq.com
    *	date	 :  2024/04/25
    * 	note	 :  none
    * 	
    * *****************************************************************/
    //创建顺序表并对顺序栈进行初始化
    SeqStack_t * SeqStack_Create(unsigned int size)
    {
    	//1.利用calloc为顺序栈的管理结构体申请一块堆内存
    	SeqStack_t *Manager = (SeqStack_t *)calloc(1,sizeof(SeqStack_t));
    
    	if(NULL == Manager)
    	{
    		perror("calloc memory for manager is failed");
    		exit(-1); //程序异常终止
    	}
    
    	//2.利用calloc为所有元素申请堆内存
    	Manager->Bottom = (DataType_t *)calloc(size,sizeof(DataType_t));
    
    	if (NULL == Manager->Bottom)
    	{
    		perror("calloc memory for Stack is failed");
    		free(Manager);
    		exit(-1); //程序异常终止
    	}
    
    	//3.对管理顺序栈的结构体进行初始化(元素容量 + 最后元素下标)
    	Manager->Size = size;	//对顺序栈中的容量进行初始化
    	Manager->Top = -1;		//由于顺序栈为空,则栈顶元素的下标初值为-1
    	
    	return Manager;
    }
    /*********************************************************************
    *
    *	name	 :	SeqStack_IsFull
    *	function : 判断顺序栈是否已满
    *	argument :  
    *				@Manager  :顺序栈的地址
    *				
    *	retval	 :  调用成功返回bool型,满了则返回true,没满返回false
    *	author	 :  790557054@qq.com
    *	date	 :  2024/04/25
    * 	note	 :  none
    * 	
    * *****************************************************************/
    bool SeqStack_IsFull(SeqStack_t *Manager)
    {
    	return (Manager->Top + 1 == Manager->Size) ? true : false;
    }
    /*********************************************************************
    *
    *	name	 :	SeqStack_Push
    *	function : 根据栈的特性,把新元素从栈顶入栈,也就是从数组的尾部进行元素插入
    *	argument :  
    *				@Manager  :顺序栈的地址
    				@Date  	  :要入栈的数据
    *				
    *	retval	 :  调用成功返回bool型,满了则返回true,没满返回false
    *	author	 :  790557054@qq.com
    *	date	 :  2024/04/25
    * 	note	 :  none
    * 	
    * *****************************************************************/
    //入栈
    bool SeqStack_Push(SeqStack_t *Manager, DataType_t Data)
    {
    	//1.判断顺序栈是否已满
    	if ( SeqStack_IsFull(Manager) )
    	{
    		printf("SeqStack Full is Full!\n");
    		return false;
    	}
    
    	//2.如果顺序栈有空闲空间,则把新元素添加到顺序栈的栈顶
    	Manager->Bottom[++Manager->Top] = Data;
    
    	return true;
    }
    
    /*********************************************************************
    *
    *	name	 :	SeqStack_IsEmpty
    *	function : 	判断顺序栈是否为空
    *	argument :  
    *				@Manager  :顺序栈的地址
    *				
    *	retval	 :  调用成功返回bool型,空了则返回true,没空返回false
    *	author	 :  790557054@qq.com
    *	date	 :  2024/04/25
    * 	note	 :  none
    * 	
    * *****************************************************************/
    bool SeqStack_IsEmpty(SeqStack_t *Manager)
    {
    	return (-1 == Manager->Top) ? true : false;
    }
    /*********************************************************************
    *
    *	name	 :	SeqStack_Pop
    *	function : 根据栈的特性,把元素从栈顶出栈,也就是把元素从数组的尾部把元素删除
    *	argument :  
    *				@Manager  :顺序栈的地址
    *				
    *	retval	 :  调用成功返回新的栈地址
    *	author	 :  790557054@qq.com
    *	date	 :  2024/04/25
    * 	note	 :  none
    * 	
    * *****************************************************************/
    //出栈
    DataType_t SeqStack_Pop(SeqStack_t *Manager)
    {
    	DataType_t temp = 0;  //用于存储出栈元素的值
    
    	//1.判断顺序栈是否为空
    	if ( SeqStack_IsEmpty(Manager) )
    	{
    		printf("SeqStack is Empty!\n");
    		return;
    	}
    	
    	//2.由于删除了一个元素,则需要让顺序栈的栈顶元素下标-1
    	temp = Manager->Bottom[Manager->Top--];
    
    	return temp;
    }
    /*********************************************************************
    *
    *	name	 :	SeqStack_Push
    *	function : 对顺序栈中的元素进行遍历,只需要从顺序栈的栈底开始向栈顶进行遍历
    *	argument :  
    *				@Manager  :顺序栈的地址
    *				
    *	retval	 :  调用成功返回bool型,满了则返回true,没满返回false
    *	author	 :  790557054@qq.com
    *	date	 :  2024/04/25
    * 	note	 :  none
    * 	
    * *****************************************************************/
    //遍历顺序表的元素
    void SeqStack_Print(SeqStack_t *Manager)
    {
    	for (int i = 0; i <= Manager->Top; ++i)
    	{
    		printf(" Stack Element[%d] = %d\n",i,Manager->Bottom[i]);
    	}
    }
    
    
    
    int main(int argc, char const *argv[])
    {
    	//创建一个容量大小为10的栈
    	SeqStack_t *SequenceStack = SeqStack_Create(10);
    
    	//入栈
    	//1.没满时
    	SeqStack_Push(SequenceStack, 10);
    	SeqStack_Push(SequenceStack, 20);
    	SeqStack_Push(SequenceStack, 30);
    	SeqStack_Push(SequenceStack, 40);
    	SeqStack_Push(SequenceStack, 50);
    	SeqStack_Push(SequenceStack, 60);
    	SeqStack_Push(SequenceStack, 70);
    	SeqStack_Push(SequenceStack, 80);
    	SeqStack_Push(SequenceStack, 90);
    	SeqStack_Push(SequenceStack, 100);
    	printf("\n");
    	//遍历显示
    	SeqStack_Print(SequenceStack);
    	printf("\n");
    	//2.满时进栈
    	SeqStack_Push(SequenceStack, 666);
    	printf("\n");
    	//遍历显示
    	SeqStack_Print(SequenceStack);
    	printf("\n");
    
    	//出栈
    	//1.有元素时出栈
    	SeqStack_Pop(SequenceStack);
    	SeqStack_Pop(SequenceStack);
    	SeqStack_Pop(SequenceStack);
    	SeqStack_Pop(SequenceStack);
    	SeqStack_Pop(SequenceStack);
    	SeqStack_Pop(SequenceStack);
    	SeqStack_Pop(SequenceStack);
    	printf("\n");
    	//遍历显示
    	SeqStack_Print(SequenceStack);
    	printf("\n");
    	SeqStack_Pop(SequenceStack);
    	SeqStack_Pop(SequenceStack);
    	SeqStack_Pop(SequenceStack);
    	printf("\n");
    	//遍历显示
    	SeqStack_Print(SequenceStack);
    	printf("\n");
    
    	//2.空时出栈
    	SeqStack_Pop(SequenceStack);
    
    
    
    	return 0;
    }
    
    
    

    结果验证:

栈(Stack)的原理与代码实现

链式栈:以链表作为基础实现栈空间

如果打算实现链式栈,一般是以链表作为基础,一般是把链表头部作为栈顶,方便数据的插入和删除(头插+头删),链式栈相当于是一个单向不循环的链表。

栈(Stack)的原理与代码实现

为了方便管理链式栈,所以需要构造链式栈的结构体类型,如下:

//指的是链式栈中的元素的数据类型,用户可以根据需要进行修改
typedef int  DataType_t;

//构造记录链式栈各项参数(栈中存储数据 + 栈顶元素的地址)的结构体
typedef struct ChainStack
{
	DataType_t              data;		//记录栈中存储数据
	struct ChainStack      *next;		//记录当前节点直接后继节点的地址

}ChaStack_t;
  1. 创建一个空的链式栈,并为记录顺序栈信息的结构体申请堆内存,并进行初始化即可!

    /********************************************************************
     *
     *	name	 :	ChainStack_Create
     *	function :  创建一个链式栈,栈顶应该连接有一个头结点,对该头结点进行初始化
     *	argument :
     *				none
     *
     *	retval	 :  调用成功返回已经完成初始化栈顶的头结点,否则退出程序
     *	author	 :  790557054@qq.com
     *	date	 :  2024/04/25
     * 	note	 :  none
     *
     * *****************************************************************/
    ChaStack_t *ChainStack_Create(void)
    {
    	// 1.创建一个头结点并对头结点申请内存
    	ChaStack_t *Head = (ChaStack_t *)calloc(1, sizeof(ChaStack_t));
    	if (Head == NULL)
    	{
    		perror("Calloc memory for Head is Failed");
    		exit(-1);
    	}
    
    	// 2.对头结点进行初始化,头结点是不存储数据域,指针域指向NULL
    	Head->next = NULL;
    
    	// 3.把头结点的地址返回即可
    	return Head;
    }
    
  2. 根据栈的特性,把新元素从栈顶入栈,也就是从链表的首部进行元素插入,操作如下:

/********************************************************************
 *
 *	name	 :	ChainStack_NewNode
 *	function :  创建新的结点,并对新结点进行初始化(数据域 + 指针域)
 *	argument :
 *				@data 新节点需要存储的数据
 *
 *	retval	 :  调用成功返回已经完成初始化的链式栈的新节点,否则返回NULL
 *	author	 :  790557054@qq.com
 *	date	 :  2024/04/25
 * 	note	 :  none
 *
 * *****************************************************************/
ChaStack_t *ChainStack_NewNode(DataType_t data)
{
	// 1.创建一个新结点并对新结点申请内存
	ChaStack_t *New = (ChaStack_t *)calloc(1, sizeof(ChaStack_t));
	if (NULL == New)
	{
		perror("Calloc memory for NewNode is Failed");
		return NULL;
	}

	// 2.对新结点的数据域和指针域进行初始化
	New->data = data;
	New->next = NULL;

	return New;
}
/********************************************************************
 *
 *	name	 :	ChainStack_Push
 *	function :  入栈,将要存储的数据,从栈顶入栈,即对链表进行头插操作
 *	argument :
 *				@Head 栈顶连接头结点
 *				@data 新节点的数据域需要存储的数据
 *
 *	retval	 :  调用成功输出"插入成功",否则输出"插入失败"
 *	author	 :  790557054@qq.com
 *	date	 :  2024/04/23
 * 	note	 :  none
 *
 * *****************************************************************/
void ChainStack_Push(ChaStack_t *Head, DataType_t data)
{
	// 定义一个循环指针变量Phead
	ChaStack_t *Phead = Head->next;
	// 调用函数创立一个新节点,并完成对应的错误处理
	ChaStack_t *New = ChainStack_NewNode(data);
	if (New == NULL)
	{
		printf("Push of %d is fail!\n", New->data);
		return;
	}

	// 进行判断,排除空链表的情况
	if (Head->next == NULL)
	{
		Head->next = New;
		printf("Push of %d is success!\n", New->data);
		return;
	}

	//1. 将新节点的next连接至首节点
    New->next = Phead;
    //2. 将头结点的next连接至新节点
    Head->next = New;

    printf("Push of %d is success!\n", New->data);

	return;
}
  1. 根据栈的特性,把元素从栈顶出栈,也就是把元素从链表的首部将元素删除,操作如下:

    /********************************************************************
     *
     *	name	 :	CircLList_HeadDel
     *	function :  出栈,将链式栈的栈顶元素删除,即链表的头删
     *	argument :
     *				@Head 栈顶连接的头结点
     *
     *	retval	 :  调用成功后让栈顶的元素出栈
     *	author	 :  790557054@qq.com
     *	date	 :  2024/04/25
     * 	note	 :  none
     *
     * *****************************************************************/
    void ChainStack_Pop(ChaStack_t *Head)
    {
    	// 对单向循环链表的头结点的地址进行备份
    	ChaStack_t *Phead = Head->next;
    
    	// 判断当前链表是否为空,为空则直接退出
    	if (Head->next == NULL)
    	{
    		printf("current linkeflist is empty!\n");
    		return;
    	}
    
    	//1. 将头结点的next连接至首节点的直接后继
        Head->next = Phead->next;
        //2. 将首节点的next指向NULL
        Phead->next = NULL;
        //3. 删除掉首节点
        free(Phead);
    
        printf("Pop is success!\n");
    
    	return;
    }
    
  2. 对链式栈中的元素进行遍历,只需要从链式栈的栈顶开始向栈底进行遍历,操作如下:

/********************************************************************
 *
 *	name	 :	ChainStack_Printf
 *	function :  遍历输出栈中已经存储的数据
 *	argument :
 *				@Head 栈顶连接的头结点
 *
 *	retval	 :  调用成功输出链表中所有节点的数据域的值
 *	author	 :  790557054@qq.com
 *	date	 :  2024/04/23
 * 	note	 :  none
 *
 * *****************************************************************/
void ChainStack_Printf(ChaStack_t *Head)
{
	// 对单向循环链表的头结点的地址进行备份
	ChaStack_t *Phead = Head;

	// 判断当前链表是否为空,为空则直接退出
	if (Head->next == NULL)
	{
		printf("current linkeflist is empty!\n");
		return;
	}

    printf("Stack Top->");
	// 从首结点开始遍历
	while (Phead->next)
	{
		// 把头结点的直接后继作为新的头结点
		Phead = Phead->next;

        // 输出头结点的直接后继的数据域
        printf("%d->", Phead->data);

		// 判断是否到达尾结点,尾结点的next指针是指向首结点的地址
		if (Phead->next == Head->next)
		{
			break;
		}
	}

    printf("Stack Bottom\n");

    return;
}

代码整体展示:

/*******************************************************************
*
*	file name:	ChainStack.c
*	author	 :  790557054@qq.com
*	date	 :  2024/04/25
*	function :  该案例是掌握链式栈的创建原理与功能实现
* 	note	 :  None
*
*	CopyRight (c)  2023-2024   790557054@qq.com   All Right Reseverd 
*
* *****************************************************************/
#include <stdio.h>
#include <stdlib.h>

//指的是链式栈中的元素的数据类型,用户可以根据需要进行修改
typedef int  DataType_t;

//构造记录链式栈各项参数(栈中存储数据 + 栈顶元素的地址)的结构体
typedef struct ChainStack
{
	DataType_t              data;		//记录栈中存储数据
	struct ChainStack      *next;		//记录当前节点直接后继节点的地址

}ChaStack_t;
/********************************************************************
 *
 *	name	 :	ChainStack_Create
 *	function :  创建一个链式栈,栈顶应该连接有一个头结点,对该头结点进行初始化
 *	argument :
 *				none
 *
 *	retval	 :  调用成功返回已经完成初始化栈顶的头结点,否则退出程序
 *	author	 :  790557054@qq.com
 *	date	 :  2024/04/25
 * 	note	 :  none
 *
 * *****************************************************************/
ChaStack_t *ChainStack_Create(void)
{
	// 1.创建一个头结点并对头结点申请内存
	ChaStack_t *Head = (ChaStack_t *)calloc(1, sizeof(ChaStack_t));
	if (Head == NULL)
	{
		perror("Calloc memory for Head is Failed");
		exit(-1);
	}

	// 2.对头结点进行初始化,头结点是不存储数据域,指针域指向NULL
	Head->next = NULL;

	// 3.把头结点的地址返回即可
	return Head;
}
/********************************************************************
 *
 *	name	 :	ChainStack_NewNode
 *	function :  创建新的结点,并对新结点进行初始化(数据域 + 指针域)
 *	argument :
 *				@data 新节点需要存储的数据
 *
 *	retval	 :  调用成功返回已经完成初始化的链式栈的新节点,否则返回NULL
 *	author	 :  790557054@qq.com
 *	date	 :  2024/04/25
 * 	note	 :  none
 *
 * *****************************************************************/
ChaStack_t *ChainStack_NewNode(DataType_t data)
{
	// 1.创建一个新结点并对新结点申请内存
	ChaStack_t *New = (ChaStack_t *)calloc(1, sizeof(ChaStack_t));
	if (NULL == New)
	{
		perror("Calloc memory for NewNode is Failed");
		return NULL;
	}

	// 2.对新结点的数据域和指针域进行初始化
	New->data = data;
	New->next = NULL;

	return New;
}
/********************************************************************
 *
 *	name	 :	ChainStack_Push
 *	function :  入栈,将要存储的数据,从栈顶入栈,即对链表进行头插操作
 *	argument :
 *				@Head 栈顶连接头结点
 *				@data 新节点的数据域需要存储的数据
 *
 *	retval	 :  调用成功输出"插入成功",否则输出"插入失败"
 *	author	 :  790557054@qq.com
 *	date	 :  2024/04/23
 * 	note	 :  none
 *
 * *****************************************************************/
void ChainStack_Push(ChaStack_t *Head, DataType_t data)
{
	// 定义一个循环指针变量Phead
	ChaStack_t *Phead = Head->next;
	// 调用函数创立一个新节点,并完成对应的错误处理
	ChaStack_t *New = ChainStack_NewNode(data);
	if (New == NULL)
	{
		printf("Push of %d is fail!\n", New->data);
		return;
	}

	// 进行判断,排除空链表的情况
	if (Head->next == NULL)
	{
		Head->next = New;
		printf("Push of %d is success!\n", New->data);
		return;
	}

	//1. 将新节点的next连接至首节点
    New->next = Phead;
    //2. 将头结点的next连接至新节点
    Head->next = New;

    printf("Push of %d is success!\n", New->data);

	return;
}
/********************************************************************
 *
 *	name	 :	CircLList_HeadDel
 *	function :  出栈,将链式栈的栈顶元素删除,即链表的头删
 *	argument :
 *				@Head 栈顶连接的头结点
 *
 *	retval	 :  调用成功后让栈顶的元素出栈
 *	author	 :  790557054@qq.com
 *	date	 :  2024/04/25
 * 	note	 :  none
 *
 * *****************************************************************/
void ChainStack_Pop(ChaStack_t *Head)
{
	// 对单向循环链表的头结点的地址进行备份
	ChaStack_t *Phead = Head->next;

	// 判断当前链表是否为空,为空则直接退出
	if (Head->next == NULL)
	{
		printf("current linkeflist is empty!\n");
		return;
	}

	//1. 将头结点的next连接至首节点的直接后继
    Head->next = Phead->next;
    //2. 将首节点的next指向NULL
    Phead->next = NULL;
    //3. 删除掉首节点
    free(Phead);

    printf("Pop is success!\n");

	return;
}
/********************************************************************
 *
 *	name	 :	ChainStack_Printf
 *	function :  遍历输出栈中已经存储的数据
 *	argument :
 *				@Head 栈顶连接的头结点
 *
 *	retval	 :  调用成功输出链表中所有节点的数据域的值
 *	author	 :  790557054@qq.com
 *	date	 :  2024/04/23
 * 	note	 :  none
 *
 * *****************************************************************/
void ChainStack_Printf(ChaStack_t *Head)
{
	// 对单向循环链表的头结点的地址进行备份
	ChaStack_t *Phead = Head;

	// 判断当前链表是否为空,为空则直接退出
	if (Head->next == NULL)
	{
		printf("current linkeflist is empty!\n");
		return;
	}

    printf("Stack Top->");
	// 从首结点开始遍历
	while (Phead->next)
	{
		// 把头结点的直接后继作为新的头结点
		Phead = Phead->next;

        // 输出头结点的直接后继的数据域
        printf("%d->", Phead->data);

		// 判断是否到达尾结点,尾结点的next指针是指向首结点的地址
		if (Phead->next == Head->next)
		{
			break;
		}
	}

    printf("Stack Bottom\n");

    return;
}

int main()
{
    //创立栈顶连接的头结点
    ChaStack_t *Head = ChainStack_Create();

    //入栈
    ChainStack_Push(Head, 10);
    ChainStack_Push(Head, 20);
    ChainStack_Push(Head, 30);
    printf("\n");

    //遍历
    ChainStack_Printf(Head);

    //出栈
    ChainStack_Pop(Head);
    ChainStack_Pop(Head);
    printf("\n");

    //遍历
    ChainStack_Printf(Head);

    ChainStack_Pop(Head);
    ChainStack_Pop(Head);


    return 0;
}

结果验证:

栈(Stack)的原理与代码实现文章来源地址https://www.toymoban.com/news/detail-857739.html

到了这里,关于栈(Stack)的原理与代码实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 举例说明PyTorch函数torch.cat与torch.stack的区别

    torch.cat 用于在 给定的维度 上连接多个张量,它将这些张量沿着指定维度堆叠在一起。 torch.stack 用于在 新的维度 上堆叠多个张量,它会创建一个新的维度,并将这些张量沿着这个新维度堆叠在一起。 Example1: Example1: Example2:

    2024年02月09日
    浏览(41)
  • C++ deque/queue/stack的底层原理

    和 vector 容器采用连续的线性空间不同,deque 容器存储数据的空间是由一段一段等长的连续空间构成,各段空间之间并不一定是连续的,可以位于在内存的不同区域。 deque采用一块所谓的map数组(注意,不是STL的map容器)作为主控。 这里所谓map是一小块连续空间 (类似于ve

    2024年02月16日
    浏览(44)
  • 【C++历练之路】stack||queue||底层原理知多少

    W...Y的主页 😊 代码仓库分享💕  🍔前言: C++标准模板库(Standard Template Library,STL)是C++语言的一个重要组成部分,提供了一组通用的数据结构和算法,以便开发人员能够高效地编写可重用的代码。STL中的两个常用容器,即stack(堆栈)和queue(队列),在许多应用中都是非

    2024年02月04日
    浏览(38)
  • C++学习:stack

    1.stack的定义和结构 stack是一种后进先出(LIF0)的数据结构,使用前需要包含头文件,stack提供了一组函数来操作和访问元素,但它的功能相对较简单。stack的定义和结构如下(仅作了解即可): T:表示存储在stack中的元素的类型。 Container:表示底层容器的类型,默认为deque。也可以使用

    2024年02月20日
    浏览(23)
  • 华为云Stack的学习(一)

    1.HCS 物理分散、逻辑统一、业务驱动、运管协同、业务感知 2.华为云Stack的特点 可靠性 包括整体可靠性、数据可靠性和单一设备可靠性。通过云平台的分布式架构,从整体系统上提高可靠性,降低系统对单设备可靠性的要求。 可用性 通过冗余、高可用集群、应用于底层设备

    2024年02月12日
    浏览(21)
  • 华为云Stack的学习(三)

    1.华为云Stack公共负载均衡方案介绍 1.1 LVS原理 LVS是四层负载均衡,建立在OSI模型的传输层之上,所以效率非常高。 LVS有两种转发模式: NAT模式的转发主要通过修改IP地址(位于OSI模型的第三层网络层)实现转发。 DR模式的转发主要通过修改MAC地址(位于OSI模型的第二层数据

    2024年02月11日
    浏览(21)
  • 华为云Stack的学习(二)

    FunsionSphere CPS 提供云平台的基础管理和业务资源(包括计算资源和存储资源)。采用物理服务器方式部署在管理节点。可以做集群的配置,扩容和运维管理。 Service OM 提供云服务的运维能力,采用虚拟化方式部署在管理节点。可以做资源管理。 FusionCare 作为健康检查和信息收

    2024年02月11日
    浏览(24)
  • 华为云Stack的学习(四)

    1.Service OM简介 1.1 Service OM介绍 在华为云Stack解决方案中,Service OM是FusionSphere OpenStack的操作管理界面,是资源池(计算、存储、网络)以及基础云服务的管理工具。 1.2 Service OM定位 Service OM向下对接FusionSphere OpenStack组件,向上对接ManageOne以及云服务。 1.3 Service OM功能分类 资源

    2024年02月10日
    浏览(31)
  • stack&queue的模拟实现

    stack模拟: stack的源代码: stack的全部源代码就这些。 stack的代码少,原因在于采用了适配器模式,所谓适配器,以电器为例,每个电器都有电源适配器,中国的家用电源为220V的交流电,但是几乎没有电器需要220V的交流电,所以每个电器都有一个电源适配器,将家庭电压转换

    2024年02月06日
    浏览(40)
  • 【C++】学习STL中的stack和queue

            今天这篇博客的内容主要关于STL中的stack、queue和priority_queue三种容器。         stack和queue的使用方式非常简单,我们只要根据之前学习数据结构的经验和文档介绍就可以轻松上手。于是我们直接开始对它们的模拟实现。         stack和queue我们在数据结构阶段就曾经

    2024年02月10日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包