Data structure---stack

1.1 The concept and structure of the stack

Stack: A special linear table that only allows inserting and deleting elements in a fixed segment. One end of the data insertion and deletion operations is called the top of the stack , and the other end is called the bottom of the stack . The data elements in the stack follow the principle of last in, first out .

Push: The insertion operation of the stack is called push/push/push, and the data is on the top of the stack

Pop: The delete operation of the stack is called pop, and the popped data is also on the top of the stack.
Insert picture description here

1.2 Implementation of the stack

The implementation of the stack can generally be implemented using an array or a linked list. Relatively speaking, the structure of an array is better to implement a stack . Because the cost of inserting data on the end of the array is relatively small.
Insert picture description here
Using an array to implement the stack, you can think that the bottom of the stack and the top of the stack are at the same position at the beginning, but the top of the stack is more like a description of the direction of the stack, indicating the direction of the data into the stack.
Insert picture description here

1.2.1 The difference and advantages and disadvantages of sequential list and linked list implementation stack

So why is it better to use an array than a linked list?
For the array structure to represent the stack, head insertion and middle insertion cannot be performed, because it will destroy the last-in, first-out feature of the stack. Then you may think: the use of sequential tables needs to increase the capacity, or it will cause a waste of space, etc...In fact, for a sequential table, it is not necessary to increase the capacity every time you insert data, and for the computer The memory is quite large, even if you waste hundreds of thousands of bytes of space, it is insignificant to him, unless you are in the embedded industry and value memory very much, then it’s a different matter. The most important thing is that the sequence table is easy to implement. If it is a doubly linked list, it is actually okay that one side is the top of the stack and the other is the bottom of the stack. But if it is a singly linked list, your head should be set to the direction of the top of the stack.
Insert picture description here
If you define the result of a singly linked list to achieve a stack like this, you will find that you insert data at the top of the stack, but when you want Pop, you don't know its previous address.
Insert picture description here

When will the stack be used?
For example, in a last-in first-out scenario, for a maze, sometimes I may go to a dead end. At this time, I hope it can return to its original position. I can use this to achieve it.

1.3 The complete code of the array implementation stack

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int STDateType;

typedef struct Stack
{
    
    
	STDateType* _a;
	int _top; //栈顶下标
	int _capacity;
}Stack;

//初始化和销毁
void StackInit(Stack* pst);
void StackDestory(Stack* pst);

//入栈
void StackPush(Stack* pst, STDateType x);
//出栈
void StackPop(Stack* pst);
//获取数据个数
int StackSize(Stack* pst);

//返回1是空,返回0是非空
int StackEmpty(Stack* pst);
//获取栈顶的数据
STDateType StackTop(Stack* pst);
#include"Stack.h"
//初始化
void StackInit(Stack* pst)
{
    
    
	assert(pst);
	//这种方式是有不好的地方的,因为但当你需要增容的时候,你就会发现,他的capacity初始化是0,那么你乘2依旧是0,所以建议一开始就给一个固定值
	//pst->_a = NULL;
	//pst->_top = 0;
	//pst->_capacity = 0;
	pst->_a = (STDateType*)malloc(sizeof(STDateType)*4);
	pst->_top = 0;
	pst->_capacity = 4;
}

//销毁
void StackDestory(Stack* pst)
{
    
    
	assert(pst);
	free(pst->_a);
	pst->_a = NULL;
	pst->_top = pst->_capacity = 0;
}

//入栈
//只要入栈就要考虑到空间是否满的情况,对其进行判断
void StackPush(Stack* pst, STDateType x)
{
    
    
	assert(pst);
	//空间不够则增容
	if (pst->_top == pst->_capacity)
	{
    
    
		pst->_capacity *= 2;
		STDateType* tmp = (STDateType*)realloc(pst->_a, sizeof(STDateType)*pst->_capacity);
		if (tmp == NULL)
		{
    
    
			printf("内存不足\n");
			exit(-1);
		}
		else
		{
    
    
			pst->_a = tmp;
		}
	}
	pst->_a[pst->_top] = x;//你所定义的栈顶总是在你放入数据的下一个位置
	pst->_top++;
}

//出栈
void StackPop(Stack* pst)
{
    
    
	assert(pst);
	assert(pst->_top > 0);//得确保栈里面是有数据的,你才能去删
	--pst->_top;
}

//获取数据个数
int StackSize(Stack* pst)
{
    
    
	assert(pst);
	return pst->_top;
}


//返回1是空,返回0是非空
int StackEmpty(Stack* pst)
{
    
    
	assert(pst);
	return pst->_top == 0 ? 1 : 0;
}


//获取栈顶的数据
STDateType StackTop(Stack* pst)
{
    
    
	assert(pst);
	assert(pst->_top > 0);
	return pst->_a[pst->_top - 1];//你所定义的栈顶总是在你放入数据的下一个位置
}
#include"Stack.h"
void TsetStack()
{
    
    
	Stack st;
	StackInit(&st);
	StackPush(&st, 1);
	StackPush(&st, 2);
	StackPush(&st, 3);
	StackPush(&st, 4)while (!StackEmpty(&st))
	{
    
    
		printf("%d ", StackTop(&st));
		StackPop(&st);
	}
	printf("\n");
	StackDestory(&st);
	
}
int main()
{
    
    
	TsetStack();
	return 0;
}

Insert picture description here

The stack does not require one-time stacking or popping, you can choose to enter and exit the stack. Therefore, a stacking sequence may correspond to multiple popping sequences.

1.4 Multiple-choice questions about the stack

1. The initial state of a stack is empty. Now put the elements 1, 2, 3, 4, 5, A, B, C, D, E into the stack in turn , and then pop out the stack in turn, the order of the elements out of the stack is (B).
A 12345ABCDE
B EDCBA54321
C
ABCDE12345 D 54321EDCBA

These answers are the results if the word "sequential" does not appear in the question, but when the word "sequential" appears, the result can only be B, push all the stacks at once, and then pop all the stacks
A: for the A option, it is the entry One stack is popped from the stack, which is the possible result.
B: Put all into the stack at once, and then pop all the stacks.
C: Impossible
D: First enter 12345 and then pop, then load ABCDE and then pop , Is a possible result

2. If the stack sequence is 1, 2, 3, 4, and the stack can be popped during the stacking process, the following impossible pop sequence is (C)
A 1,4,3,2
B 2,3,4 ,1
C 3,1,4,2
D 3,4,2,1
Answer:
A: First enter 1, out 1, then enter 2, 3, 4 and pop out of the stack. This is a possible result.
B: First in 1, 2, then out of stack 2, then in 3, out of 3, in 4 out of 4, and finally out 1, which is a possible result.
C: Impossible.
D enters 1, 2, 3 out of 3, then enters 4, out of 4, and then out of 2, 1 is a possible result.

1.5 LeetCode question 20-valid parentheses

Insert picture description here
Insert picture description here
For C++, you have a stack, but for C language, there is no stack. You need to implement a stack yourself.

typedef char STDateType;

typedef struct Stack
{
    
    
	STDateType* _a;
	int _top; //栈顶下标
	int _capacity;
}Stack;

//初始化和销毁
void StackInit(Stack* pst);
void StackDestory(Stack* pst);

//入栈
void StackPush(Stack* pst, STDateType x);
//出栈
void StackPop(Stack* pst);
//获取数据个数
int StackSize(Stack* pst);

//返回1是空,返回0是非空
int StackEmpty(Stack* pst);
//获取栈顶的数据
STDateType StackTop(Stack* pst);

//初始化
void StackInit(Stack* pst)
{
    
    
	assert(pst);
	pst->_a = (STDateType*)malloc(sizeof(STDateType)*4);
	pst->_top = 0;
	pst->_capacity = 4;
}

//销毁
void StackDestory(Stack* pst)
{
    
    
	assert(pst);
	free(pst->_a);
	pst->_a = NULL;
	pst->_top = pst->_capacity = 0;
}

//入栈
void StackPush(Stack* pst, STDateType x)
{
    
    
	assert(pst);
	//空间不够则增容
	if (pst->_top == pst->_capacity)
	{
    
    
		pst->_capacity *= 2;
		STDateType* tmp = (STDateType*)realloc(pst->_a, sizeof(STDateType)*pst->_capacity);
		if (tmp == NULL)
		{
    
    
			printf("内存不足\n");
			exit(-1);
		}
		else
		{
    
    
			pst->_a = tmp;
		}
	}
	pst->_a[pst->_top] = x;//你所定义的栈顶总是在你放入数据的下一个位置
	pst->_top++;
}

//出栈
void StackPop(Stack* pst)
{
    
    
	assert(pst);
	assert(pst->_top > 0);
	--pst->_top;
}

//获取数据个数
int StackSize(Stack* pst)
{
    
    
	assert(pst);
	return pst->_top;
}


//返回1是空,返回0是非空
int StackEmpty(Stack* pst)
{
    
    
	assert(pst);
	return pst->_top == 0 ? 1 : 0;
}


//获取栈顶的数据
STDateType StackTop(Stack* pst)
{
    
    
	assert(pst);
	assert(pst->_top > 0);
	return pst->_a[pst->_top - 1];//你所定义的栈顶总是在你放入数据的下一个位置
}




bool isValid(char * s){
    
    
    Stack  st;
    StackInit(&st);
    while(*s != '\0')
    {
    
    
        //如果是前括号那就入栈,如果是后括号那就拿栈顶的值和此时相比较(这样他们两个才是相邻的)
        if(*s == '[' || *s == '(' || *s == '{')
        {
    
    
            StackPush(&st,*s);
            s++;
        }
        else
        {
    
    
            //表示此时前括号栈里没有了,但是]还有  []]]
            if(StackEmpty(&st))
               return false; 

            
            //取栈顶
            char top = StackTop(&st);
            if(*s == ']' && top != '[')
                return false;
            if(*s == ')' && top != '(')
                return false;
            if(*s == '}' && top != '{')
                return false;
            StackPop(&st);
            s++;
        }
    }  
    //这里的while循环结束有两种情况:一种就是你的s遍历完了, 这种情况[[[]   [在栈里面还有。还有一种就是都匹配上了,里面不再有任何东西了
    //这里判断的是[[[] 在栈里面还有,但是你的s已经遇见了'\0'遍历完了
    int ret = StackEmpty(&st);
    // ret如果为1表示空,此时所有的括号都匹配上了,1就代表true,但是ret加上下面这个ret==0这个判断条件更加容易理解,如果他是0表示[在栈里面还有,但是此时s已经遍历完了,所以他不为空,那么也是一种错误的情况
    if(ret == 0)
      return false;
    //在你把栈使用完了以后一定要对其进行释放,否则就会造成内存的泄漏
    StackDestory(&st);
    return ret;
}

Insert picture description here

Guess you like

Origin blog.csdn.net/MEANSWER/article/details/112465209