An article to teach you to understand-data structure stack and queue


Due to space issues, the author put the code at the end of the article, and readers can extract it by themselves.

① stack

Insert picture description here

栈(stack)是限定 仅在表尾进行插人或删除操作的线性表。因此,对栈来说,表尾
端有其特殊含义,称为栈顶(top),相应地,表头端称为栈底(bottom)。不含元素的空表称"
为空栈。

假设栈S=(a1,a2...,an,),则称as为栈底元素,a。为栈顶元素。栈中元素按a1,
a2,..,an的次序进栈,退栈的第-一个元素应为栈顶元素。换句话说,栈的修改是按后进
先出的原则进行的(如图3.1(a)所示)。因此,栈又称为后进先出(lastinfirstout)的线
性表(简称LIFO结构),它的这个特点可用图3.1(b)所示的铁路调度站形象地表示。

Definition of abstract data type stack

In addition to inserting or deleting at the top of the stack, the basic operations of the stack include initialization of the stack, empty determination, and access to the top element
of the stack. The definition of the abstract data type of the stack is given below:
Insert picture description here

Representation and implementation of the stack

The order of stack storage is probably similar to that of arrays. Readers only need to record the position of the top element on the stack (structure arrays can be used). Below we focus on the implementation of chain storage.
The following is the definition of the structure in the chain storage:
* struct stack{ int value; // the value in the stack struct stack next; }; int num




InitList(); // Create an empty stack
For chain storage, it is to create a single structure with a special value (such as 0, which means no element) and next is null, and return the head pointer. Here, head is defined as the head pointer of the stack, and the global variable num is used to record the length of the stack.
DestroyStack(); // Destroy the stack
Use the free function in the malloc function package-free(head)
stack *ClearStack(); // Set head to empty stack
. Assign the next value of head to null, that is, delete all stack elements afterwards.
IfEmpty(); // Determine whether it is an empty stack
, that is, only need to determine the value of num, if it is 0, it is an empty stack, and vice versa.
StackLength(); // Return the length of the stack Return the length of
num
GetTop(); // Return the top element of the stack, if the stack is empty, return 0
to return the top element of the stack, that is, return the value value when p->next = null
Push(); //
Add a structure data to the stack element and connect it to the end of the stack
Pop(); // If the stack is not empty, delete the top element of the
stack. Return the top element of the stack, that is, return the value of p->next = null, and delete the pointer at the end.
Below is a screenshot of the result of running the code
Insert picture description here

②The application example of the stack

Expression evaluation

1. The rules of
expression evaluation Expression evaluation is a basic problem in programming language compilation. Its realization is a typical application of the "stack".

  首先了解算术四则运算的运算规则:

 (1)先乘除,后加减。

 (2)从左到右计算

 (3)先算括号内,再算括号外

  因此,下面这个算数表达式的计算顺序应为:

  4 + 2 * 3 - 10 / 5

  = 4 + 6 - 10 / 5

  = 10 - 10 / 5

  = 10 - 2

  = 8

任何一个表达式都由操作数(operand)、运算符(operator)和界定符组成:

① Operands can be constants or identifiers that are described as variables or constants.

② Operators can be divided into arithmetic operations, relational operations and logical operators.

③The delimiter includes left and right brackets and end symbols.

  为了叙述的简洁,我们仅讨论简单算数表达式的求值问题,这种表达式只包含加、减、乘、除等四种算术运算。需要时
  ,不难把它推广到更一般的表达式上。

2. Operator precedence
There are three relations for two successive operators θ1 and θ2:

θ1 <θ2    θ1的优先级低于θ2

θ1 =θ2    θ1的优先级等于θ2

θ1 >θ2    θ1的优先级高于θ2

由此可以列出“+-*/”之间的优先级。如下图

Insert picture description here
It can be seen from the figure that the priority of addition, subtraction, multiplication and division is lower than "(" but higher than ")". From left to right, we can see that when θ1=θ2, let θ1>θ2;

为了算法简洁,在表达式的左边和右边虚设一个“#”,这一对“#”表示一个表达式求值完成。

“(”=“)”当一对括号相遇时表示括号内已运算完成。

 “)”和“(”、“#”和“(”、“(”和“#”无法相继出现,如果出现则表达式出现语法错误。(实现时,可以用0存储)

这个表如何理解呢?例如:a+b+c,这里有两个运算符,运算符θ1 为+,运算符θ2 也为+ ,查上表,得到“>”的关系,那么意味着先计算前面的+号,也就是先算a+b,得到结果后,再考虑算后面的表达式。

3. Algorithm idea In
order to realize the priority algorithm, two work stacks can be used, one is OPTR, which is used to register operators, and the other is OPND, which is used to register operands and operation results. The basic idea of ​​the algorithm is:

(1) 首先置操作数栈为空栈,表达式起始符'#'为栈底元素。

(2)依次读入表达式中的每个字符,若是操作数则进OPND栈,若是运算符则和OPTR栈的栈顶运算符比较优先级作相应操作,直至整个表达式求值完毕(OPTR栈顶元素和当前读入的字符均为'#')

算数表达式求值的运算符优先算法。假定输入的表达式语法正确,以'#'做结束符。使用OPTR和OPND分别作为运算符栈和操作数栈。

expression函数的算法逻辑如下。以下是伪代码,需要用真实的代码代替:

setNull(OPTR);

push(OPTR,'#'); //Push'#' onto the OPTR stack

setNull(OPND);

Read the character ch;

do{

  if (ch IN op) //op为运算符的集合

        swith( precede(top(OPTR),ch ) { //比较栈顶元素和ch的优先关系

        case '<':

              push(OPTR,ch);  //栈顶元素优先级低,则压入操作符栈

              读入字符ch;

              break;

        case '=':

              if (ch==')') 

              x = pop(OPTR);   //自己思考什么情况需要这个判断

              读入字符ch;

              break;

        case '>'://栈顶元素优先级高,取出一个运算符,两个操作数,并计算

              theta = pop(OPTR);

              b = pop(0PND);

              a = pop(OPND);

              push(OPND,operate(a, theta, b));//将计算结果压入操作数栈

  }

  else{   //op为操作数的集合

        push(OPND,ch);

        读入字符ch;

  }

}while (( ch != ‘#’) OR ( top(OPTR) != ‘#’))

return top(OPND);

算法中调用了两个函数,precede是判断运算符栈的栈顶运算符与读入的运算符之间的优先关系;

operate作一元运算:a θ b,算出运算结果,例如调用operate('1', '+', '5');算出结果6。

The author also found a good explanation video for everyone on this question b station, which is useful for personal testing. Here attach the evaluation of the connection expression

③Queue

Definition of abstract data type queue

Insert picture description here

Insert picture description here
Insert picture description here

Chain queue

Similar to linear tables, queues can also have two storage representations.
The queue represented by the linked list is called the chain queue for short, as shown in Figure 3.10. A chain queue obviously needs two pointers to
indicate the head and tail of the team (called the head pointer and the tail pointer respectively) to be uniquely determined. Here,
like the singly linked list of the linear table , for the convenience of operation, we also add a head node to the chain queue and make the head pointer point to the head node.
Therefore, the judgment condition of an empty chain queue is that both the head pointer and the tail pointer point to the head node, as shown in Figure 3.11(a).
The operation of the chain queue is the special case of inserting and deleting the singly linked list, but the tail pointer or the head
pointer still needs to be modified . Figure 3.11(b)~(d) shows the situation of pointer changes during these two operations. The
module description of the chain queue type is given below .
Insert picture description here
The definition of the basic operation of the chain queue, you can refer to the definition of the abstract data type stack, the same is similar. In view of the difficulty of space and content, the author will help you explain the realization of the circular queue. As for the chain queue, I look at the textbook and believe that after the circular queue is understood, the problem of the chain queue will be easily solved.

Circular queue

Here is a classic schematic diagram of the circular queue in the textbook, and the author can just taste the book carefully for the specific text. Here we focus on the points that need to be paid attention to in the implementation of functions corresponding to different operations. The circular queue is to change some places on the basis of the sequential stack. I believe that after understanding the first program attached later, the author can also complete this part of the code by himself. The following provides you with the definition and description of the basic operation of the queue.
Insert picture description hereInsert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here

Finally the code

Sequential implementation of the stack

#include<stdio.h>
#include<malloc.h>
#define LEN sizeof(struct stack)
struct stack{
    
    
	int value;	// 栈内的数值 
	struct stack *next;
};
int num;	// 全局变量,记录栈顶元素的序号
int main()
{
    
    
	struct stack *InitList();	// 创造一个空栈
	void DestroyStack(struct stack *head);	// 摧毁栈
	struct stack *ClearStack(struct stack *head);	// 将head置为空栈
	bool IfEmpty();	// 判断是否为空栈
	int StackLength();	// 返回栈的长度
	int GetTop(struct stack *head);		// 返回栈顶元素,如果栈为空则返回0
	void Push(struct stack *head,int element);	// 进栈element
	int Pop(struct stack *head);	// 若栈不空,删除栈顶元素
	
	// 测试
	struct stack *head;		// 创造栈指针
	int element,length;
	head = InitList();
	Push(head,1);
	Push(head,2);
	element = Pop(head);
	length = StackLength();
	head = ClearStack(head);
	DestroyStack(head);
}

struct stack *InitList()	// 创造一个栈
{
    
    
	// 创造一个栈
	struct stack *head;
	head = (struct stack*)malloc(LEN);
	head->value = 0;
	head->next = NULL;
	num = 0;	// 栈元素的位置为0,即空栈
	return head;
}

void DestroyStack(struct stack *head)
{
    
    
	// 摧毁栈
	free(head);
	printf("delete stack successfully!\n");
}

struct stack *ClearStack(struct stack *head)
{
    
    
	// 将head置为空栈
	head->value = 0;
	head->next = NULL;
	printf("reset successfully!\n");
	return head;
}

bool IfEmpty()
{
    
    
	// 判断是否为空栈	
	bool flag;
	if(num == 0){
    
    
		flag = true;
		printf("stack is empty!\n");
	}else{
    
    
		printf("stack is not empty!\n");
		flag = false;
	}
	return flag;
}

int StackLength()
{
    
    
	// 返回栈的长度
	int length;
	length = num;
	return length;
}

int GetTop(struct stack *head)
{
    
    
	// 返回栈顶元素,如果栈为空则返回0
	struct stack *p;
	int element;
	p = head;
	while(head->next != NULL){
    
    
		p = p->next;
	}
	element = p->value;
	return element;
}

void Push(struct stack *head,int element)
{
    
    
	// 进栈element
	struct stack *p,*add;
	add = (struct stack*)malloc(LEN);
	add->value = element;
	add->next = NULL;
	p = head;
	while(p->next != NULL){
    
    
		p = p->next;
	}
	p->next = add;
	num = num + 1;
}	

int Pop(struct stack *head)
{
    
    
	// 若栈不空,删除栈顶元素
	struct stack *p;
	bool flag;
	int element;
	p = head;
	flag = IfEmpty();
	if(flag == false){
    
    
		element = 0;
		printf("stack is empty! error!\n");
	}else{
    
    
		while(p->next->next != NULL){
    
    
			p = p->next;
		}
		element = p->value;
		p->next = NULL;
		num = num - 1;
	}
	return 0;
}	

Guess you like

Origin blog.csdn.net/wlfyok/article/details/113967064