Stack and queue introduction and basic functions from theory to practice

Posted by webtechatlantic on Tue, 18 Jan 2022 05:43:40 +0100

Content guide

1. Stack

1.1 overview of stack

1.2 several concepts of stack

1.3 characteristics of stack

1.4 examples of stack

1.5 basic functions of stack

1.6 stack classification

1.7 implementation header file of basic functions of sequence stack

1.8 node declaration of sequential stack

1.9 basic function realization and related theory of sequence stack

1.9.1 about top

1.9.2 four elements of sequence stack

1.9.3 schematic diagram of stacking in and out of sequence stack

1.10 basic function practice of sequence stack

1.10.1 sequence stack initialization

1.10.2 sequential stack destruction

1.10.3 empty judgment of sequence stack

1.10.4 stacking

1.10.5 out of stack

1.10.6 stack top elements

1.10.7 printing elements in stack

1.10.8 number of effective elements of stack

1.10. Final sequence stack code set

2. Queue

2.1 queue overview

2.2 several concepts of queue

2.3 queue characteristics

2.4 basic functions of queue

2.5 classification of queues

2.6 implementation header file of basic functions of chain team

2.7 chain team node declaration

2.8 theories related to the realization of the basic functions of the chain team

2.8.1 schematic diagram of chain team

2.8.2 composition of chain team

2.8.3 entry and exit of chain team

2.8.4 four elements of chain team

2.9 implementation practice of basic functions of chain team

2.9.1 chain team initialization

2.9.2 chain team destruction

2.9.3 entry and exit of chain team

2.9.4 obtaining team head and tail data

2.9.5 obtain the number of effective elements of the chain team

2.9.6 chain air judgment

2.9. Final chain team code collection

1. Stack

1.1 overview of stack

A stack is a linear table that can only be inserted or deleted at one end.

1.2 several concepts of stack

  • The end that allows insertion and deletion is called the top of the stack.
  • The other end of the table is called the bottom of the stack.
  • When there are no data elements in the stack, it is called an empty stack.
  • The insertion of a stack is usually called pushing or pushing.
  • The deletion of stack is usually called out of stack or out of stack.

1.3 characteristics of stack

The main feature of stack is "last in first out", that is, the elements of last in stack are first out of stack. Stacks are also called last in first out tables.

1.4 examples of stack

If the input sequence of a stack is a, b, c, d, the output sequence obtained by means of a stack cannot be ().

A. c,d,b,a                         B. d,c,b,a  

C. a,c,d,b                        ​​​​​ D. d,a,b,c   

The input sequence of a stack is 1, 2, 3,..., n, and its output sequence is p1, p2, p3,..., pn. If p1=3, what are the possible values of p2?

A.n-3 , B.n-2 , C.n-1 , D

The input sequence of a stack is 1, 2, 3,..., n, and its output sequence is p1, p2, p3,..., pn. If p2=3, what are the possible values of p3 ()?

A.n-3 , B.n-2 , C.n-1 , D

1.5 basic functions of stack

Stackinit & initializes the stack. Construct an empty stack s.
Stackdestroy & destroy stack. Release the storage space occupied by stack s.
StackEmpty(s): judge whether the stack is empty: if stack s is empty, it returns true; Otherwise, false is returned.
Stackpush (& S, e): stack. Insert the element E into the stack s as the top element of the stack.
Stackpop & S, & e: out of stack. Exit the stack top element from stack s and assign its value to e.
StackGetTop(s, & e): fetch stack top element. Returns the current stack top element and assigns its value to e.

StackPrint(sqStack* ps): prints the elements in the stack
StackSize(sqStack* ps): gets the number of elements in the stack

1.6 stack classification

The logical relationship of the elements in the stack is the same as that of the linear table. The stack can adopt the same storage structure as the linear table.

Therefore, there are two implementation forms of stack, one is the form of sequential list, and the other is the form of linked list.

Use the sequence table to realize the function of the stack, which is called the sequence stack. Similarly, using chain storage structure to realize the function of stack is called chain stack. Using the sequence stack, you can simply realize the functions of entering and leaving the stack, which is equivalent to inserting and deleting the tail of the original sequence table. It is quite appropriate to use the tail of the sequence table as the top of the stack. The only disadvantage is capacity expansion and memory waste. When using a chain stack, you need to consider whether to use the tail as the top of the stack or the head as the top of the stack. If you use the tail as the top of the stack, it is better to use a double linked list, otherwise it is better to use a single linked list.

This article will implement some basic functions of the stack in the form of sequential stack.

1.7 implementation header file of basic functions of sequence stack

#pragma once
/*Basic functions of sequence stack:
	StackInit(&s): Initialize stack. Construct an empty stack s.
  StackDestroy(&s): Destroy the stack. Release the storage space occupied by stack s.
  StackEmpty(s): Judge whether the stack is empty: if the stack s is empty, return true; Otherwise, false is returned.
  StackPush(&S,e): Get in the stack. Insert the element e into the stack s as the top element of the stack.
  StackPop(&s,& e): Out of the stack. Exit the stack top element from stack s and assign its value to e.
  StackGetTop(s,& e): Take the top element of the stack. Returns the current stack top element and assigns its value to e.*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

typedef int StackType;
typedef struct Stack
{
	StackType *data;
	int top;
	int capacity;
}sqStack;
void StackInit(sqStack *ps); //Initialize stack. Construct an empty stack s.
void StackDestroy(sqStack *ps);// Destroy the stack. Release the storage space occupied by stack s.
bool StackEmpty(sqStack* ps);// Judge whether the stack is empty: if the stack s is empty, return true; Otherwise, false is returned.
void StackPush(sqStack* ps,StackType e);// Get in the stack. Insert the element e into the stack s as the top element of the stack.
void StackPop(sqStack* ps,StackType *e);// Out of the stack. Exit the stack top element from stack s and assign its value to e.
StackType StackGetTop(sqStack* ps,StackType *e);// Take the top element of the stack. Returns the current stack top element and assigns its value to e.
void StackPrint(sqStack* ps);//Print elements in stack
int StackSize(sqStack* ps);//Gets the number of elements in the stack

1.8 node declaration of sequential stack

typedef int StackType;
typedef struct Stack
{
	StackType *data;//data
	int top;        //Stack top pointer
	int capacity;    //Stack capacity
}sqStack;

1.9 basic function realization and related theory of sequence stack

1.9.1 about top

  • The Convention top always points to the top element of the stack, and the initial value is - 1 (or 0)
  • When the stack capacity is full, you cannot enter the stack again - the stack is full. If you need to enter the stack, you need to expand the capacity of the sequential stack
  • top increases by 1 when entering the stack and decreases by 1 when leaving the stack

1.9.2 four elements of sequence stack

  • Stack empty condition: top=-1 (top can also be zero, but it should be noted that the stack full condition and stack empty condition will change. In this paper, top=1 is taken as the chestnut)
  • Stack full condition: top=capacity - 1
  • Stack e operation: Top + +; Place e at the top
  • Stack withdrawal: take out the element E from the top; top--;

1.9.3 schematic diagram of stacking in and out of sequence stack

Stack entry (capacity expansion is required when the stack is full)

Out of stack (stack cannot be empty)

1.10 basic function practice of sequence stack

1.10.1 sequence stack initialization

 //Initialize stack. Construct an empty stack s.
 //1. Give the sequence stack a certain data capacity 2 Initialize top
void StackInit(sqStack* ps)
{
	assert(ps);
	ps->data = (StackType*)malloc(sizeof(StackType) * 4);
	ps->capacity = 4;
	ps->top = -1;
}

1.10.2 sequential stack destruction

// Destroy the stack. Release the storage space occupied by stack ps.
void StackDestroy(sqStack* ps)
{
	assert(ps);
	free(ps->data);
	ps->data = NULL;
	ps->top = ps->capacity = NULL;
}

1.10.3 empty judgment of sequence stack

// Judge whether the stack is empty: if the stack s is empty, return true; Otherwise, false is returned.
bool StackEmpty(sqStack* ps)
{
	assert(ps);

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

1.10.4 stacking

// Get in the stack. Insert the element e into the stack s as the top element of the stack.
void StackPush(sqStack* ps, StackType e)
{
	assert(ps);
	//If the stack is full, it needs to be expanded
	if (ps->top == ps->capacity - 1) {
		StackType* tmp = (StackType*)realloc(ps->data, ps->capacity * 2 * sizeof(StackType));
		if (tmp == NULL) {
			printf("Capacity expansion failed!\n");
			exit(-1);
		}
		else {
			ps->data = tmp;
			ps->capacity *= 2;
		}
	}
	ps->top++;
	ps->data[ps->top] = e;
}

1.10.5 out of stack

// Out of the stack. Exit the stack top element from stack s and assign its value to e.
void StackPop(sqStack* ps, StackType* e)
{
	assert(ps);
	assert(ps->top > -1);
	*e = ps->data[ps->top];
	ps->top--;
	//printf("out of stack% d\n", *e);
}

1.10.6 stack top elements

// Take the top element of the stack. Returns the current stack top element and assigns its value to e.
StackType StackGetTop(sqStack* ps, StackType* e)
{
	assert(ps);
	assert(ps->top > -1);
	e = ps->data[ps->top];
	return e;
}

1.10.7 printing elements in stack

//Print elements in stack
void StackPrint(sqStack* ps)
{
	assert(ps);
	int i = ps->top;
	while(i > -1) {
		printf("%d\n", ps->data[i]);
		i--;
	}
}

1.10.8 number of effective elements of stack

//Gets the number of elements in the stack
int StackSize(sqStack* ps)
{
	assert(ps);
	return ps->top + 1;
}

1.10. Final sequence stack code set

#include "sqStack.h"
 //Initialize stack. Construct an empty stack s.
void StackInit(sqStack* ps)
{
	assert(ps);
	ps->data = (StackType*)malloc(sizeof(StackType) * 4);
	ps->capacity = 4;
	ps->top = -1;
}
// Destroy the stack. Release the storage space occupied by stack s.
void StackDestroy(sqStack* ps)
{
	assert(ps);
	free(ps->data);
	ps->data = NULL;
	ps->top = ps->capacity = NULL;
}
// Judge whether the stack is empty: if the stack s is empty, return true; Otherwise, false is returned.
bool StackEmpty(sqStack* ps)
{
	assert(ps);

	if (ps->top == -1) 
		return true;
	else
		return false;
}
// Get in the stack. Insert the element e into the stack s as the top element of the stack.
void StackPush(sqStack* ps, StackType e)
{
	assert(ps);
	//If the stack is full, it needs to be expanded
	if (ps->top == ps->capacity - 1) {
		StackType* tmp = (StackType*)realloc(ps->data, ps->capacity * 2 * sizeof(StackType));
		if (tmp == NULL) {
			printf("Capacity expansion failed!\n");
			exit(-1);
		}
		else {
			ps->data = tmp;
			ps->capacity *= 2;
		}
	}
	ps->top++;
	ps->data[ps->top] = e;
}
// Out of the stack. Exit the stack top element from stack s and assign its value to e.
void StackPop(sqStack* ps, StackType* e)
{
	assert(ps);
	assert(ps->top > -1);
	*e = ps->data[ps->top];
	ps->top--;
	printf("Out of stack%d\n", *e);
}
// Take the top element of the stack. Returns the current stack top element and assigns its value to e.
StackType StackGetTop(sqStack* ps, StackType* e)
{
	assert(ps);
	assert(ps->top > -1);
	e = ps->data[ps->top];
	return e;
}
//Print elements in stack
void StackPrint(sqStack* ps)
{
	assert(ps);
	int i = ps->top;
	while(i > -1) {
		printf("%d\n", ps->data[i]);
		i--;
	}
}
//Gets the number of elements in the stack
int StackSize(sqStack* ps)
{
	assert(ps);
	return ps->top + 1;
}

2. Queue

2.1 queue overview

Queue is called queue for short. It is also a linear table with limited operation.

2.2 several concepts of queue

  • The end of the insertion is called the tail.
  • The end at which the deletion is made is called the head of the team or the head of the team.
  • Inserting a new element into the queue is called queue entry or queue entry. After entering the queue, the new element becomes a new tail element.
  • Deleting an element from a queue is called out of the queue or out of the queue. After an element is out of the queue, its successor element becomes the first element of the team.  

2.3 queue characteristics

Queue is mainly characterized by first in first out, so it is also called first in first out table.

2.4 basic functions of queue

//Initialize queue
void QueueInit(Queue* pq);
//Destroy queue
void QueueDestory(Queue* pq);
//Team tail in
void QueuePush(Queue* pq,QueueDataType x);
//Head to head
void QueuePop(Queue* pq);
//Get header data
QueueDataType QueueFront(Queue* pq);
//Get tail data
QueueDataType QueueBack(Queue* pq);
//Gets the number of valid elements of the queue
int QueueSize(Queue* pq);
//Determine whether the queue is empty
bool QueueEmpty(Queue* pq);

2.5 classification of queues

The logical relationship of the elements in the queue is the same as that of the linear table. The queue can adopt the same storage structure as the linear table.

Therefore, queues can also be implemented using sequential lists or chained storage structures.

However, it is better to use the structure of linked list, because if the structure of array is used, the efficiency will be low.

Therefore, this paper will realize some basic functions of queue in the form of chain team.

2.6 implementation header file of basic functions of chain team

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int QueueDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QueueDataType data;
}QNode;
typedef struct Queue
{
	QNode* head;
	QNode* tail;
}Queue;
//Initialize queue
void QueueInit(Queue* pq);
//Destroy queue
void QueueDestory(Queue* pq);
//Team tail in
void QueuePush(Queue* pq,QueueDataType x);
//Head to head
void QueuePop(Queue* pq);
//Get header data
QueueDataType QueueFront(Queue* pq);
//Get tail data
QueueDataType QueueBack(Queue* pq);
//Gets the number of valid elements of the queue
int QueueSize(Queue* pq);
//Determine whether the queue is empty
bool QueueEmpty(Queue* pq);

2.7 chain team node declaration

typedef int QueueDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QueueDataType data;
}QNode;//This node is a single linked list node of the chain team
typedef struct Queue
{
	QNode* head;
	QNode* tail;
}Queue;//This node is a pointer structure pointing to the head and tail of the chain queue node

2.8 theories related to the realization of the basic functions of the chain team

The queue stored in the linked list is called the chain queue, which is realized by the single linked list without the leading node.

2.8.1 schematic diagram of chain team

2.8.2 composition of chain team

(1) Single linked list node for storing queue elements

(2) Chain queue node pointing to the head and tail of the queue

2.8.3 entry and exit of chain team

The chain team enters the team from the end of the team, which is equivalent to inserting at the end of the single chain table, and leaving the team from the head of the team, which is equivalent to deleting the single chain header.

The time complexity is O (1)

2.8.4 four elements of chain team

  • Air condition: head=tail=NULL
  • Team full condition: not considered
  • Queue e operation: insert the node containing e into the end of the single linked list
  • Out of queue operation: delete the data node at the head of the single link table

2.9 implementation practice of basic functions of chain team

2.9.1 chain team initialization

Construct an empty queue, that is, only one chain queue head node is created, its head and tail fields are set to NULL, and no data element node is created.

//Initialize queue
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;

}

2.9.2 chain team destruction

Release the storage space occupied by the queue, including the storage space of the chain queue head node and all data nodes.

//Destroy queue
void QueueDestory(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
}

2.9.3 entry and exit of chain team

Consideration when entering the team:

  1. The original queue is empty
  2. Original queue is not empty
//Team tail in
void QueuePush(Queue* pq,QueueDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL) {
		printf("newnode fail!");
		exit(-1);
	}
	else {
		newnode->data = x;
		newnode->next = NULL;
	}
	if (pq->tail == NULL) {
		pq->tail = newnode;
		pq->head = newnode;
	}
	else {
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}

Considerations for leaving the team:

  1. The original queue is empty
  2. The original queue has only one node
  3. Other situations
//Head to head
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->head);
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;

	}
	else {
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
}

2.9.4 obtaining team head and tail data

//Get header data
QueueDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->head);
	return pq->head->data;
}
//Get tail data
QueueDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->tail);
	return pq->tail->data;
}

2.9.5 obtain the number of effective elements of the chain team

//Gets the number of valid elements of the queue
int QueueSize(Queue* pq)
{
	assert(pq);
	if (pq->head == NULL)
		return 0;
	QNode* cur = pq->head;
	int size = 0;
	while (cur) {
		size++;
		cur = cur->next;
	}
	return size;
}

2.9.6 chain air judgment

If the tail or head field value of the chain queue node is NULL, it indicates that the queue is empty and returns true; Otherwise, false is returned.

//Determine whether the queue is empty
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return(pq->head == NULL);
}

2.9. Final chain team code collection

#include "QueueNode.h"
//Initialize queue
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;

}
//Destroy queue
void QueueDestory(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
}
//Team tail in
void QueuePush(Queue* pq,QueueDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL) {
		printf("newnode fail!");
		exit(-1);
	}
	else {
		newnode->data = x;
		newnode->next = NULL;
	}
	if (pq->tail == NULL) {
		pq->tail = newnode;
		pq->head = newnode;
	}
	else {
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}
//Head to head
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->head);
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;

	}
	else {
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
}
//Get header data
QueueDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->head);
	return pq->head->data;
}
//Get tail data
QueueDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->tail);
	return pq->tail->data;
}
//Gets the number of valid elements of the queue
int QueueSize(Queue* pq)
{
	assert(pq);
	if (pq->head == NULL)
		return 0;
	QNode* cur = pq->head;
	int size = 0;
	while (cur) {
		size++;
		cur = cur->next;
	}
	return size;
}
//Determine whether the queue is empty
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return(pq->head == NULL);
}

Topics: data structure linked list queue stack