Un article pour vous apprendre à comprendre la pile et la file d'attente de la structure des données


En raison de problèmes d'espace, l'auteur a mis le code à la fin de l'article et les lecteurs peuvent l'extraire eux-mêmes.

① pile

Insérez la description de l'image ici

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

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

Définition de la pile de types de données abstraites

Outre l'insertion ou la suppression en haut de la pile, les opérations de base de la pile comprennent l'initialisation de la pile, la détermination du vide et l'accès à l'élément supérieur
de la pile. La définition du type de données abstrait de la pile est donnée au dessous de:
Insérez la description de l'image ici

Représentation et mise en œuvre de la pile

L'ordre de stockage de la pile est probablement similaire à celui des tableaux. Les lecteurs n'ont qu'à enregistrer la position de l'élément supérieur sur la pile (des tableaux de structure peuvent être utilisés). Ci-dessous, nous nous concentrons sur la mise en œuvre du stockage en chaîne.
Voici la définition de la structure dans la chaîne de stockage:
* struct stack { int value; // la valeur de la pile struct stack next; }; int num




InitList (); // Créer une pile vide
Pour le stockage en chaîne, il s'agit de créer une structure unique avec une valeur spéciale (telle que 0, ce qui signifie aucun élément) et next est nul, et renvoyer le pointeur de tête. Ici, head est défini comme le pointeur de tête de la pile, et la variable globale num est utilisée pour enregistrer la longueur de la pile.
DestroyStack (); // Détruire la pile
Utiliser la fonction free dans la fonction malloc package-free (head)
pile * ClearStack (); // Définit head sur une pile vide
. Assigne la valeur suivante de head à null, c'est-à-dire supprime tous les éléments de la pile par la suite.
IfEmpty (); // Détermine s'il s'agit d'une pile vide
, c'est-à-dire qu'il suffit de déterminer la valeur de num, si elle est 0, c'est une pile vide, et vice versa.
Longueur de pile (); // Renvoie la longueur de la pile Renvoie la longueur de
num
GetTop (); // Retourne l'élément du haut de la pile, si la pile est vide, retourne 0
pour renvoyer l'élément du haut de la pile, c'est-à-dire renvoie la valeur de la valeur lorsque p-> next = null
Pousser(); //
Ajoute une donnée de structure à l' élément de pile et connecte-la à la fin de la pile
Pop(); // Si la pile n'est pas vide, supprimez l'élément du haut de la
pile. Renvoyez l'élément du haut de la pile, c'est-à-dire renvoyez la valeur de p-> next = null, et supprimez le pointeur à la fin.
Ci-dessous se trouve une capture d'écran du résultat de l'exécution du code
Insérez la description de l'image ici

②L'exemple d'application de la pile

Évaluation d'expression

1. Les règles d'
évaluation des expressions L'évaluation des expressions est un problème fondamental dans la compilation des langages de programmation. Sa réalisation est une application typique de la "pile".

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

 (1)先乘除,后加减。

 (2)从左到右计算

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

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

  4 + 2 * 3 - 10 / 5

  = 4 + 6 - 10 / 5

  = 10 - 10 / 5

  = 10 - 2

  = 8

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

① Les opérandes peuvent être des constantes ou des identificateurs décrits comme des variables ou des constantes.

② Les opérateurs peuvent être divisés en opérations arithmétiques, opérations relationnelles et opérateurs logiques.

③Le délimiteur comprend des crochets gauche et droit et des symboles de fin.

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

2. Priorité des opérateurs
Il existe trois relations pour deux opérateurs successifs θ1 et θ2:

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

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

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

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

Insérez la description de l'image ici
On peut voir sur la figure que la priorité d'addition, de soustraction, de multiplication et de division est inférieure à "(" mais supérieure à ")". De gauche à droite, on peut voir que lorsque θ1 = θ2, soit θ1> θ2;

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

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

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

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

3. Idée d'algorithme
Afin de réaliser l'algorithme de priorité, deux piles de travail peuvent être utilisées, l'une est OPTR, qui est utilisée pour enregistrer les opérateurs, et l'autre est OPND, qui est utilisée pour enregistrer les opérandes et les résultats d'opérations. L'idée de base de l'algorithme est:

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

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

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

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

setNull (OPTR);

push (OPTR, '#'); // Poussez '#' sur la pile OPTR

setNull (OPND);

Lisez le caractère ch;

faire{

  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)! = '#'))

retour haut (OPND);

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

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

L'auteur a également trouvé une bonne vidéo d'explication pour tout le monde sur cette station question b, ce qui est utile pour les tests personnels. Joindre ici l' évaluation de l'expression de connexion

③Queue

Définition de la file d'attente de type de données abstrait

Insérez la description de l'image ici

Insérez la description de l'image ici
Insérez la description de l'image ici

File d'attente de la chaîne

À l'instar des tables linéaires, les files d'attente peuvent également avoir deux représentations de stockage.
La file d'attente représentée par la liste chaînée est appelée file d'attente en chaîne pour faire court, comme le montre la figure 3.10. Une file d'attente en chaîne a évidemment besoin de deux pointeurs pour
indiquer la tête et la queue de l'équipe (appelées respectivement le pointeur de tête et le pointeur de queue) à déterminer de manière unique. Ici,
comme la liste à liaison unique de la table linéaire , pour la commodité de l'opération, nous ajoutons également un nœud de tête à la file d'attente de la chaîne et faisons pointer le pointeur de tête vers le nœud de tête.
Par conséquent, la condition de jugement d'une file d'attente de chaîne vide est que le pointeur de tête et le pointeur de queue pointent vers le nœud de tête, comme le montre la figure 3.11 (a).
Le fonctionnement de la file d'attente en chaîne est le cas particulier de l'insertion et de la suppression de la liste liée à un seul lien, mais le pointeur de queue ou le
pointeur de tête doit encore être modifié . deux opérations. La
description du module du type de file d'attente en chaîne est donnée ci-dessous .
Insérez la description de l'image ici
La définition du fonctionnement de base de la file d'attente de la chaîne, vous pouvez vous référer à la définition de la pile de type de données abstraite, la même chose est similaire. Au vu de la difficulté d'espace et de contenu, l'auteur vous aidera à expliquer la réalisation de la file d'attente circulaire. Quant à la file d'attente en chaîne, je regarde le manuel et je crois qu'après avoir compris la file d'attente circulaire, le problème de la file d'attente en chaîne sera facilement résolu.

File d'attente circulaire

Voici un diagramme schématique classique de la file d'attente circulaire dans le manuel, et l'auteur peut simplement goûter le livre avec soin pour le texte spécifique. Nous nous concentrons ici sur les points auxquels il faut prêter attention dans la mise en œuvre de fonctions correspondant à différentes opérations. La file d'attente circulaire est de changer certains endroits sur la base de la pile séquentielle.Je crois qu'après avoir compris le premier programme attaché plus tard, l'auteur peut également compléter cette partie du code par lui-même. Ce qui suit vous donne la définition et la description du fonctionnement de base de la file d'attente.
Insérez la description de l'image iciInsérez la description de l'image ici
Insérez la description de l'image ici
Insérez la description de l'image ici
Insérez la description de l'image ici
Insérez la description de l'image ici
Insérez la description de l'image ici

Enfin le code

Implémentation séquentielle de la pile

#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;
}	

Je suppose que tu aimes

Origine blog.csdn.net/wlfyok/article/details/113967064
conseillé
Classement