• 【数据结构】栈的实现


    🚩纸上得来终觉浅, 绝知此事要躬行。
    🌟主页:June-Frost
    🚀专栏:数据结构

    🔥该文章主要了解实现栈的相关操作。

    🌍 栈的概念

     栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素——压栈和出栈都是在栈顶。

    🌎栈的实现

     栈的实现一般可以使用数组或者链表实现,如果使用数组,以尾部为栈顶,压栈和出栈的时间消耗都为O(1),唯一的缺陷就是需要扩容。如果考虑单链表,若以尾节点为栈顶,那么时间复杂度为O(N),如果以头节点为栈顶,时间复杂度就是O(1)。相较于链表,数组结构的缓存利用率较高,相对而言更优一些。这里采用数组结构实现。
      结构体:

    typedef int STDataType;
    typedef struct Stack
    {
    	STDataType* arr;
    	int capacity; // 记录容量
    	int top;//栈顶
    }ST;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ✉️ 初始化栈 和 销毁栈

    void STInit(ST* ps)
    {
    	assert(ps);
    	ps->arr = NULL;
    	ps->top = ps->capacity = 0;
    }
    
    void STDestroy(ST* ps)
    {
    	assert(ps);
        free(ps->arr);
    	ps->arr = NULL;
    	ps->capacity = ps->top = 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

     这里将top初始化为0,意味着top标记的是栈顶元素的下一个元素。top如果初始化为-1,那么标记的就是栈顶元素,初始化的不同,后续相关操作的实现方式也是不同的。

    ✉️ 入栈

    void STPush(ST* ps, STDataType x)
    {
    	assert(ps);
    	//扩容
    	if (ps->top == ps->capacity)
    	{
    		int newCapacity = ps->capacity == 0 ? 4: ps->capacity * 2;
    		//如果 ps->a 为NULL,realloc的功能和malloc一样 
    		STDataType* tmp = (STDataType*)realloc(ps->arr, sizeof(STDataType) * newCapacity);
    		if (tmp == NULL)
    		{
    			perror("realloc fail");
    			exit(-1);
    		}
    		ps->arr = tmp;
    		ps->capacity = newCapacity;
    	}
    	ps->arr[ps->top] = x;
    	ps->top++;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    ✉️ 出栈

    void STPop(ST* ps)
    {
    	assert(ps->top > 0 && ps);
    	ps->top--;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ✉️ 获取栈顶元素

    STDataType STTop(ST* ps)
    {
    	assert(ps->top > 0 && ps);
    	return ps->arr[ps->top-1];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ✉️ 获取栈中有效元素个数

    void STSize(ST* ps)
    {
    	assert(ps);
    	return ps->top;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ✉️ 判空

    bool STEmpty(ST* ps)
    {
    	assert(ps);
    	return ps->top == 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ✉️ 接口测试

     这样的逻辑就可以实现栈的特性。

    void test()
    {
    	ST st;
    	STInit(&st);
    	STPush(&st, 1);
    	STPush(&st, 2);
    	STPush(&st, 3);
    	STPush(&st, 4);
    	STPush(&st, 5);
    	STPush(&st, 6);
    	STPush(&st, 7);
    	STPush(&st, 8);
    	while (!STEmpty(&st))
    	{
    		printf("%d ", STTop(&st));
    		STPop(&st);
    	}
    	STDestroy(&st);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    ❤️ 结语

     文章到这里就结束了,如果对你有帮助,你的点赞将会是我的最大动力,如果大家有什么问题或者不同的见解,欢迎大家的留言~

  • 相关阅读:
    数仓分层能减少重复计算,为啥能减少?如何减少?这篇文章包懂!
    Tomcat HTTPS证书申请与部署
    ES6 模块化
    【总结】I/O接口中的数据线,地址线,控制线,状态线传输什么信息?
    产业互联网的内在逻辑就是借助新技术的方式来改造传统
    有监督学习——高斯过程
    Blend for Visual Studio 让XAML也可以像WinForm一样可视化设计,Blend 与Studio的区别
    2022年最新海南机动车签字授权人模拟考试及答案
    eyb:Vue学习3
    使用Aggregated APIServer扩展你的kubernetes API
  • 原文地址:https://blog.csdn.net/m0_75219751/article/details/133618405