Introduction and Implementation of Data Structure Introduction (C Language Edition) Stack and Queue Stack

insert image description here

The concept of stack

Stack: A special linear list that only allows insertion and deletion of elements at a fixed end. The end where data insertion and deletion operations are performed 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 LIFO (Last In First Out).
Push stack: The insertion operation of the stack is called push/push/push, and the incoming data is at the top of the stack .
Popping: The deletion operation of the stack is called popping. The output data is also on the top of the stack .
insert image description here

The implementation process of the stack

Stacks can be implemented using two main data structures: arrays and linked lists.

A stack implemented using an array is called a sequential stack (or static stack), and the time complexity of its basic operations is O(1). During implementation, an array of a certain size needs to be pre-allocated as storage space. When the number of elements in the stack exceeds the size of the array, an expansion operation is required.

A stack implemented using a linked list is called a linked stack (or dynamic stack), and the time complexity of its basic operations is also O(1). Compared with the sequential stack, the linked stack has no fixed size limit, and nodes can be added and deleted dynamically, so the implementation is more flexible.

In addition to the above two main data structures, there are some other data structures that can be used to implement stacks, such as doubly linked lists. But in practical applications, arrays and linked lists are the two most common stack implementations.

Stack structure and interface definition

1. Static stack structure

The fixed-length static stack structure
code is as follows:

typedef int STDataType;
#define N 10
typedef struct Stack
{
    
    
 STDataType _a[N];
 int _top; // 栈顶
}Stack;

2. Dynamic stack structure

Static structure is generally not practical in practice, so we mainly implement the following stack that supports dynamic growth
. The code is as follows:

typedef int STDataType;
typedef struct Stack
{
    
    
	STDataType* a;
	int top;     //栈顶
	int capacity;//容量
}ST;

Although dynamic expansion is used here
, the sequential structure is still used to implement the stack
for beginners to understand

3. Interface definition of the stack

code show as below:

void StackInit(ST* ps);//初始化栈
void StackPush(ST* ps, STDataType x);//入栈
void StackPop(ST* ps);// 出栈
STDataType StackTop(ST* ps);// 获取栈顶元素
int StackSize(ST* ps);// 获取栈中有效元素个数
bool StackEmpty(ST* ps);// 检测栈是否为空,如果为空返回ture,如果不为空返回false
void StackDestroy(ST* ps);// 销毁栈

It can be seen that the interface function of the stack is much simpler than the previous sequence table and linked list.
In fact, it is also very simple to implement. Next, we implement these interfaces

Stack interface implementation

① Initialize the stack (StackInit)

code show as below:

void StackInit(ST* ps)
{
    
    
	assert(ps);
	ps->a = NULL;
	ps->top = 0; // ps->top = -1;
	ps->capacity = 0;
}

The initialization of the stack first sets the elements to empty, and the top of the stack points to 0. Of course, you can also point to -1. The subsequent interface functions should also be adjusted accordingly. You can set it according to your own habits. There is no fixed standard, and then the capacity is initialized to 0.

②Into the stack (StackPush)

code show as below:

void StackPush(ST* ps, STDataType x)
{
    
    
	assert(ps);

	if (ps->top == ps->capacity)
	{
    
    
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
    
    
			printf("realloc fail\n");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newCapacity;
	}
	ps->a[ps->top] = x;
	ps->top++;
}

The writing method of pushing into the stack is a bit similar to the tail insertion of the sequence table. First, it is a classic ternary operator to judge the capacity. If the capacity is not enough, it will increase the capacity, and then apply for space from the memory. The if here is to prevent the application from failing and no interrupt can be found. A hint written by the reason, similar to an assertion, inserts the element, increases the capacity, and then points the top of the stack to the new element, and the top of the stack ++ completes the stack operation.

③Pack (StackPop)

code show as below:

void StackPop(ST* ps)
{
    
    
	assert(ps);
	assert(!StackEmpty(ps));//判断是否为空

	ps->top--;
}

The popping here is very simple, first make an assertion, the StackEmpty function here will be implemented later, directly top– to complete the stacking operation.

④StackTop

code show as below:

STDataType StackTop(ST* ps)
{
    
    
	assert(ps);
	assert(!StackEmpty(ps));

	return ps->a[ps->top - 1];
}

To return the top value of the stack, you only need to return a[highest subscript]. If you initialize and define top=-1, then here is
the value of ps->a[ps->top].

⑤Number of stack elements (StackSize)

code show as below:

int StackSize(ST* ps)
{
    
    
	assert(ps);

	return ps->top;
}

The number of stack elements can directly return the top value. If you initialize and define top=-1, then here is the value of top++

⑥ Check whether the stack is empty (StackEmpty)

code show as below:

bool StackEmpty(ST* ps)
{
    
    
	assert(ps);

	if (ps->top == 0)
	{
    
    
		return true;
	}
	else
	{
    
    
		return false;
	}
}

First, the return type can be int. Here I use the bool type, which is the same, but I return the logical value true or false. If it is empty, it returns true, and if it is not empty, it returns false. There is a more concise way of this code,
the code is as follows:

bool StackEmpty(ST* ps)
{
    
    
	assert(ps);
	return ps->top == 0;
}

It also returns logical values, which is more concise and efficient.

⑦ destroy the stack (StackDestroy)

code show as below:

void StackDestroy(ST* ps)
{
    
    
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}

To realize the destruction of the stack, first release the space occupied by the elements, and then empty it for initialization.

epilogue

In fact, whether it is a stack or a queue, the implementation method is also very simple. Although it is simple, it is also an equally important knowledge point. It must be well understood and mastered. This is the end of this section. In the next section, we will talk about the concept of queues. and interface implementation.

It is not easy to make, please point out if there are any inaccuracies, thank you for your visit, UU watching is the motivation for me to persevere, under the catalyst of time, let us become better people from each other! ! !
Please add a picture description

Guess you like

Origin blog.csdn.net/kingxzq/article/details/130051648