Un artículo para enseñarle a comprender la estructura de datos y la cola


Debido a problemas de espacio, el autor puso el código al final del artículo y los lectores pueden extraerlo por sí mismos.

① apilar

Inserte la descripción de la imagen aquí

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

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

Definición de pila de tipos de datos abstractos

Además de insertar o eliminar en la parte superior de la pila, las operaciones básicas de la pila incluyen la inicialización de la pila, la determinación de vacío y el acceso al elemento superior
de la pila. Se proporciona la definición del tipo de datos abstracto de la pila debajo:
Inserte la descripción de la imagen aquí

Representación e implementación de la pila

El orden de almacenamiento de la pila es probablemente similar al de las matrices. Los lectores solo necesitan registrar la posición del elemento superior en la pila (se pueden usar matrices de estructura). A continuación, nos centramos en la implementación del almacenamiento en cadena.
La siguiente es la definición de la estructura en la cadena de almacenamiento:
* struct stack { int valor; // el valor en la pila struct stack next; }; int num




InitList (); // Crear una pila vacía
Para el almacenamiento en cadena, es crear una estructura única con un valor especial (como 0, lo que significa que no hay elemento) y siguiente es nulo, y devolver el puntero principal. Aquí, la cabeza se define como el puntero de la cabeza de la pila, y la variable global num se utiliza para registrar la longitud de la pila.
DestroyStack (); // Destruye la pila
Usa la función libre en la función malloc package-free (head)
pila * ClearStack (); // Establecer head en pila vacía
. Asignar el siguiente valor de head a null, es decir, eliminar todos los elementos de la pila después.
IfEmpty (); // Determinar si es una pila vacía
, es decir, solo es necesario determinar el valor de num, si es 0 es una pila vacía, y viceversa.
StackLength (); // Devuelve la longitud de la pila Devuelve la longitud de
num
GetTop (); // Devuelve el elemento superior de la pila, si la pila está vacía, devuelve 0
para devolver el elemento superior de la pila, es decir, devuelve el valor valor cuando p-> siguiente = nulo
Empujar(); //
Agrega una estructura de datos al elemento de la pila y conéctalo al final de la pila
Música pop(); // Si la pila no está vacía, elimina el elemento superior de la
pila. Devuelve el elemento superior de la pila, es decir, devuelve el valor de p-> siguiente = nulo y elimina el puntero al final.
A continuación se muestra una captura de pantalla del resultado de ejecutar el código
Inserte la descripción de la imagen aquí

②El ejemplo de aplicación de la pila

Evaluación de expresión

1. Las reglas de
evaluación de expresiones La evaluación de expresiones es un problema básico en la compilación de lenguajes de programación. Su realización es una aplicación típica de la "pila".

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

 (1)先乘除,后加减。

 (2)从左到右计算

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

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

  4 + 2 * 3 - 10 / 5

  = 4 + 6 - 10 / 5

  = 10 - 10 / 5

  = 10 - 2

  = 8

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

① Los operandos pueden ser constantes o identificadores que se describen como variables o constantes.

② Los operadores se pueden dividir en operaciones aritméticas, operaciones relacionales y operadores lógicos.

③ El delimitador incluye corchetes izquierdos y derechos y símbolos finales.

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

2. Precedencia de operadores
Hay tres relaciones para dos operadores sucesivos θ1 y θ2:

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

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

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

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

Inserte la descripción de la imagen aquí
Se puede ver en la figura que la prioridad de suma, resta, multiplicación y división es menor que "(" pero mayor que ")". De izquierda a derecha, podemos ver que cuando θ1 = θ2, sea θ1> θ2;

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

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

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

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

3. Idea del algoritmo
Para realizar el algoritmo de prioridad, se pueden usar dos pilas de trabajo, una es OPTR, que se usa para registrar operadores, y la otra es OPND, que se usa para registrar operandos y resultados de operaciones. La idea básica del algoritmo es:

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

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

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

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

setNull (OPTR);

push (OPTR, '#'); // Empuje '#' en la pila OPTR

setNull (OPND);

Lea el carácter ch;

hacer{

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

volver arriba (OPND);

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

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

El autor también encontró un buen video explicativo para todos en esta estación de pregunta b, que es útil para pruebas personales. Adjunte aquí la evaluación de la expresión de conexión

③ Cola

Definición de cola de tipo de datos abstractos

Inserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

Cola de cadena

Al igual que las tablas lineales, las colas también pueden tener dos representaciones de almacenamiento.
La cola representada por la lista enlazada se llama cola de cadena para abreviar, como se muestra en la Figura 3.10. Una cola de cadena obviamente necesita dos punteros para
indicar la cabeza y la cola del equipo (llamado puntero de cabeza y puntero de cola respectivamente) para ser determinado de forma única. Aquí, al
igual que la lista enlazada individualmente de la tabla lineal , para la conveniencia de la operación, también agregamos un nodo principal a la cola de la cadena y hacemos que el puntero principal apunte al nodo principal.
Por lo tanto, la condición de juicio de una cola de cadena vacía es que tanto el puntero principal como el indicador final apunten al nodo principal, como se muestra en la Figura 3.11 (a).
La operación de la cola de cadena es el caso especial de insertar y eliminar la lista enlazada individualmente, pero el puntero de cola o el
puntero de cabeza aún necesitan ser modificados . La Figura 3.11 (b) ~ (d) muestra la situación de los cambios de puntero durante estos dos operaciones. La
descripción del módulo del tipo de cola de cadena se proporciona a continuación .
Inserte la descripción de la imagen aquí
La definición de la operación básica de la cola de cadena, puede referirse a la definición de la pila de tipos de datos abstractos, lo mismo es similar. En vista de la dificultad de espacio y contenido, el autor te ayudará a explicar la realización de la cola circular. En cuanto a la cola en cadena, miro el libro de texto y creo que después de que se entiende la cola circular, el problema de la cola en cadena se resolverá fácilmente.

Cola circular

Aquí hay un diagrama esquemático clásico de la cola circular en el libro de texto, y el autor puede simplemente probar el libro con cuidado para el texto específico. Aquí nos enfocamos en los puntos a los que se debe prestar atención en la implementación de funciones correspondientes a diferentes operaciones. La cola circular es para cambiar algunos lugares sobre la base de la pila secuencial Creo que después de entender el primer programa adjunto más adelante, el autor también puede completar esta parte del código por sí mismo. A continuación, se proporciona la definición y descripción del funcionamiento básico de la cola.
Inserte la descripción de la imagen aquíInserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

Finalmente el código

Implementación secuencial de la pila

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

Supongo que te gusta

Origin blog.csdn.net/wlfyok/article/details/113967064
Recomendado
Clasificación