Data structure -- implementation of stack

Posted by keefy on Sat, 13 Nov 2021 03:09:51 +0100

1, What is stack

Structure and concept of stack: a special linear table that allows inserting and deleting elements only at a fixed end. One end for data insertion and deletion 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 LIFO (Last In First Out).
Stack pressing: the stack insertion operation is called stack pushing / stack pressing / stack pushing, and the input data is on the stack.
Stack out: stack deletion is called stack out. The output data is also at the top of the stack.


2, Implementation of stack

1. Each module

For stack, we use sequential table (that is, array implementation)
Why do we use a sequential list instead of a linked list?
    the reason is that the sequence table is naturally consistent with the stack structure. Inserting data only needs to be done at the end, and deleting data does not need to free up space. Looking at the linked table, inserting data and deleting data are relatively troublesome. Of course, it can be realized with the linked list, but this time we are talking about using the sequence table. Let's see what modules are needed to realize a stack

The code is as follows:

//The data type stored in the stack is to be renamed
//Why rename?
//Because if you want to change the content of stored data to other types such as char or double in the future, you only need to do it here once,
//It does not need to change every part of the code, which reduces unnecessary trouble and improves the readability of the code
typedef int STDataType;

typedef struct Stack
{
	STDataType* a;//Here, a pointer is used to point to the address of the stack
	int top;		// Stack top
	int capacity;  // capacity 
}Stack;
// Initialization stack 
void StackInit(Stack* ps);
// Push  
void StackPush(Stack* ps, STDataType data);
// Out of stack 
void StackPop(Stack* ps);
// Get stack top element 
STDataType StackTop(Stack* ps);
// Gets the number of valid elements in the stack 
int StackSize(Stack* ps);
// Check whether the stack is empty. If it is empty, a non-zero result is returned. If it is not empty, 0 is returned 
bool StackEmpty(Stack* ps);
// Destroy stack 
void StackDestroy(Stack* ps);

2. Implementation of each module

The code is as follows:

// Initialization stack 
void StackInit(Stack* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}
// Push  
void StackPush(Stack* ps, STDataType data)
{
	assert(ps);
	if (ps->capacity == ps->top)//Judge whether the stack is full. If it is full, it will be further expanded
	{
		int newcapacity = ps->capacity == 0 ? 4 : (ps->capacity) * 2;//The special case where capacity is 0 should be considered here. If capacity is not 0, the original capacity will be doubled
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(int)*newcapacity);
		if (!tmp)//If the expansion fails, give a prompt and terminate the program abnormally
		{
			printf("realloc fail\n");
			exit(-1);//exit(0) indicates normal termination of the program, while exit(-1) indicates abnormal termination of the program
		}
		ps->a = tmp;//If the expansion is successful, tmp is assigned to a
		ps->capacity = newcapacity;//capacity should also be updated
	}
	ps->a[ps->top++] = data;//Equivalent to PS - > a [PS - > Top] = data;
	                        //ps->top++;
}
// Out of stack 
void StackPop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));//In general, whether the stack is empty or not needs to be judged in the process of getting out of the stack and getting the top elements below, because there are no elements in the stack. How can we get out of the stack or get the top elements,           
	                          //Let's be a little violent here and assert it directly
	                          //If you want to solve it gently, you can also do this if (stack empty (PS))
	                          //                               {
	                          //                                  printf("Stack Empty\n");
	                          //                                  return;  Direct return
    ps->top--;  //We only need to reduce the top by 1 to delete the data. The data will be deleted the next time we insert the data 
                //Will be overwritten by new data
}
// Get stack top element 
STDataType StackTop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));
	return ps->a[ps->top - 1];//The top position is the next data storage position, so it needs to be reduced by 1,
	                          //Note that this is not PS - > Top --. If this is done, it means that the top element of the stack is taken and deleted
}
// Gets the number of valid elements in the stack 
int StackSize(Stack* ps)
{
	assert(ps);
	return ps->top;//The top position is the next position to store data, because the array is calculated from the subscript of 0,
	                   //So you can directly return to top without subtracting 1
}
// Check whether the stack is empty. If it is empty, a non-zero result is returned. If it is not empty, 0 is returned 
bool StackEmpty(Stack* ps)
{
	assert(ps);
	return ps->top == 0;
}
// Destroy stack 
void StackDestroy(Stack* ps)
{
	assert(ps);
	free(ps->a);//Release the space pointed to by pointer a. because the space pointed to by pointer a is opened dynamically, it should be released manually
	a = NULL;//Set a to NULL to prevent it from being dereferenced and causing the program to crash
	ps->capacity = ps->top = 0;
}

3 test procedure

The code is as follows:

void test()
{
	Stack ST;
	StackInit(&ST);
	StackPush(&ST, 1);
	StackPush(&ST, 2);
	StackPush(&ST, 3);
	StackPush(&ST, 4);//Stack 4 times
	printf("%d\n", StackSize(&ST));//Number of data stored in the print stack
	StackPush(&ST, 5);
	StackPush(&ST, 6);//Re stack 2 times
	printf("%d\n", StackSize(&ST));
	StackPop(&ST);//Take the last element out of the stack
	StackPush(&ST, 7);//Put 7 into the stack, and the data 6 in the stack will be overwritten by 7
	while (!StackEmpty(&ST))//Print the data in the stack until the stack is empty
	{
		printf("%d ", StackTop(&ST));
		StackPop(&ST);//If the last data is not out of the stack, the top will not change, and the last element will always be printed, resulting in an endless loop
	}
	printf("\n");

	StackDestroy(&ST);//Free up space
}

int main()
{
	test();

	return 0;
}

Test:


Drawing analysis:

summary

We use the sequential list to implement the stack this time, but compared with the sequential list, it is relatively troublesome to use the linked list.
In the implementation of the stack, there are 7 modules such as entering the stack and leaving the stack. When implementing stacking, we need to consider whether the capacity needs to be expanded and whether the capacity is a special case. When going out of the stack, we should consider whether there is data in the stack. If there is no data (it is unreasonable to go out of the stack without data, such as going to the supermarket to buy things without money), how can we solve this problem.
In fact, stack is widely used in daily life,
For example, stack can be applied to compiler programs such as bracket matching, line editor, expression evaluation, algorithm first grammar, etc.

Topics: data structure stack