Data structure sample code and its explanation - stack and queue

Stacks and Queues

StackStack

last in first out

​ The structure definition and basic operations of the stack.

#define MaxSize 50
typedef struct {
    
    
	int data[MaxSize];//栈中存放数据类型为整型
	int top;//栈顶指针
}Stack;

initialization

​ When initializing here, the top pointer of the stack points to -1, and some points to 0, so the code for subsequent push and pop is slightly different

void InitStack(Stack& S) {
    
    //初始化栈
	S.top = -1;
}

Check if the stack is empty

int IsEmpty(Stack S) {
    
    //判断栈是否为空
	if (S.top == -1)
		return 1;
	else
		return 0;
}

push operation

  1. Since the top pointer of the stack points to -1 initially, it is necessary to change the top pointer of the stack first, and then push it into the stack;
  2. And when MaxSize is 50, the data field is in data[0]~data[49], so here is S.top == MaxSize - 1 means the stack is full;
  3. Lines 4-5 can be combined as S.data[++S.top]=x.
int Push(Stack& S, int x) {
    
    //压栈操作
	if (S.top == MaxSize - 1)//若栈满则无法压栈
		return 0;
	S.top++;
	S.data[S.top] = x;
	return 1;
}

pop operation

  1. Here, the popped element is received by x, received first when popped, and then the top pointer of the stack is decremented
  2. Lines 4-5 can be combined as x=S.data[++S.top]
int Pop(Stack& S, int& x) {
    
    //出栈操作
	if (S.top == -1)//若栈空则无法出栈
		return 0;
	x = S.data[S.top];
	S.top--;
	return 1;
}

read the top element of the stack

​ Here, the elements popped out of the stack are received by x

int GetTop(Stack S, int& x) {
    
    //读取栈顶元素
	if (S.top == -1)//若栈空则无栈顶元素
		return 0;
	x = S.data[S.top];
	return 1;
}

​ Of course, the above is a sequential stack, and there is also a chain stack, which is similar to a single-linked list. The leading node is the stack head, and the other side is the bottom of the stack. Both stacking and stacking are performed at the head node, which is convenient for operation.

01 There is a singly linked list L with a head node. The node structure is composed of two fields, data and next, among which the data field is character type. Try to design an algorithm to judge whether all n characters in the linked list are centrosymmetric. For example, xyx and xyyx are both centrosymmetric.
  1. To judge whether this type is centrally symmetric, the stack is generally used;
  2. In this question, it is divided into two parts, the front and back, and the first half is pushed onto the stack in turn. When the second half is reached, it is compared with the elements that are popped out of the stack. After the comparison, the pointer on the top of the stack moves. traverse pointer movement;
  3. error proneAfter the for loop is pushed onto the stack, the position of i is the position after the top element of the stack, and i- is required to return it to the top position of the stack
  4. When the number of nodes is even, it will be processed normally; when the number is odd, the middle element will not be pushed onto the stack, and the traversal pointer will go one step further, bypassing the middle element;
int central_symmetry(LinkList L, int n) {
    
    
	char S[n / 2];//定义字符型数组来作为一个栈
	int i;//定义栈顶指针
	LNode* p = L->next;//定义遍历指针
    //对称轴左边字符依次入栈
	for (i = 0; i < n / 2; i++) {
    
    
		S[i] = p->data;
		p = p->next;
	}
	i--;//变量 i 返回栈顶位置
	if (n % 2 == 1) {
    
    //若字符数为奇数则 p 向后遍历一步,因为最中间字符不需考虑
		p = p->next;
	}
	while (p != NULL) {
    
    //对称轴右边字符依次与栈顶元素比对
		if (p->data == S[i]) {
    
    //与栈顶元素相等则 p 继续遍历与下一出栈元素比较
			i--;//出栈
			p = p->next;//继续遍历
		}
		else//若不等,则说明 n 个字符不对称,直接返回 0
			return 0;//非中心对称
	}
	return 1;//若正常跳出循环,则证明 n 个字符对称,返回 1
}
02 Assume that an arithmetic expression contains two types of brackets, parentheses and square brackets, write an algorithm to judge whether the brackets in the expression are paired, assuming that the arithmetic expression is stored in a character array, and the character '\0' is used as the arithmetic The terminator of the expression.
  1. In this question, no operations are required for numbers and operators
  2. The switch statement is executed sequentially from top to bottom, so break is required to jump out;
  3. When encountering a right parenthesis, you must first determine whether the stack is empty, if it is empty, it means that there is a mismatch;
  4. If the stack is empty after the array traversal is completed, it proves that all left parentheses are successfully paired
int BracketsCheck(char a[]) {
    
    
	Stack S;
	InitStack(S);
	char x;
	for (int i = 0; a[i] != '\0'; i++) {
    
    
		switch (a[i]) {
    
    
			case'('://若数组元素为左括号,则压栈继续遍历
				push(S, a[i]);
				break;
			case'[':
				push(S, a[i]);
				break;
			case')'://若元素为右括号,则需考虑是否有左括号与之配对
				if (IsEmpty(S) {
    
    
					return 0;//若栈空,则说明无左括号与之配对
				}
				else {
    
    
					Pop(S, x);
					if (x != '(') {
    
    //若栈不为空,则判断栈顶元素与当前括号是否配对
						return 0;
					}
                    //配对上了
					break;
				}
			case']':
				if (IsEmpty(S)) {
    
    
					return 0;
				}
				else {
    
    
					Pop(S, x);
					if (x != '[') {
    
    
						return 0;
					}
					break;
				}
			default://若数组元素不是括号则直接继续遍历
				break;
		}
	}
	if (IsEmpty(S)) {
    
    //若数组遍历完成后栈为空,则证明所有左括号全部配对成功
		return 1;
	}
	else {
    
    //若栈不为空,则证明有左括号未配对
		retun 0;
	}
}
03 The two stacks S1 and S2 both adopt the sequential stack method and share a storage area [0,...,MaxSize-1]. In order to maximize the use of space and reduce the possibility of overflow, the storage method with the top of the stack facing each other and growing head-on can be used. Try to design and write out the definition of this stack and the operation algorithms of S1 and S2 related to stacking and popping.

​ Two stacks require two stack top pointers. The top array is defined here, one top[0] and one top[1]

#define MaxSize 50
typedef struct{
    
    
	int data[MaxSize];
	int top[2];//一个top[0],一个top[1]指针
}DStack;

initialization

void InitDStack(DStack& S) {
    
    
	S.top[0] = -1;//初始化 S1 栈顶指针
	S.top[1] = MaxSize;//初始化 S2 栈顶指针
}

stack

  1. Because a storage space has two stacks, it is necessary to tell which stack is to be pushed into the stack, and i is used to distinguish which stack;
  2. Here S[1] represents the lower stack, and S[2] represents the upper stack
int push(int i, int x) {
    
    
	if (i < 0 || i>1) {
    
    
		return 0;//若 i 的输入不合法,则无法入栈
	}
	if (S.top[1] - S.top[0] == 1) {
    
    //若存储空间已满,则无法进行入栈操作
		return 0;
	}
	switch (i) {
    
    
		case 0:// S1 栈顶指针上移后入栈
			S.top[0]++;
			S.data[S.top[0]] = x;
			//S.data[++S.top[0]] = x;
			break;
		case 1:// S2 栈顶指针下移后入栈
			S.top[1]--;
			S.data[S.top[1]] = x;
			//S.data[--S.top[1]] = x;
			break;
	}
	return 1;
}

pop out

int pop(int i, int& x) {
    
    
	if (i < 0 || i>1) {
    
    
		return 0;
	}
	if (S.top[0] == -1 || S.top[1] == MaxSize) {
    
    //空栈
		return 0;
	}
	switch (i) {
    
    
        case 0:
            x = S.data[S.top[0]];
            S.top[0]--;//下面的栈往下移
            //x = S.data[S.top[0]--];
            break;
        case 1:
            x = S.data[S.top[1]];
            S.top[1]++;//上面的栈顶指针往上移
            //x = S.data[S.top[1]++];
            break;
        }
	return 1;
}

Queue Queue

first in first out

​ The structure definition of the queue and its basic operations.

#define MaxSize 50
typedef struct {
    
    
	int data[MaxSize];//队列中存放数据类型为整型
	int front, rear;//队首指针和队尾指针
}Queue;
void InitQueue(Queue& Q) {
    
    //初始化队列
	Q.front = 0;
	Q.rear = 0;
}
int IsEmpty(Queue Q) {
    
    //判断队列是否为空
	if (Q.front == Q.rear)//若队首指针和队尾指针指向同一位置,则队列为空
		return 1;
	else
		return 0;
}

Enqueue and Dequeue

Here, the pointer at the end of the queue points to the next position of the element. For details, see Enqueue and Dequeue Operations

When entering the team, it is the pointer at the end of the team that needs to be判断队满Q.rear == MaxSize

//顺序队列的入队和出队:
//这里队尾指针指向元素的后一个位置
int EnQueue(Queue& Q, int x) {
    
    //入队操作
	if (Q.rear == MaxSize)//若队满,则无法入队
		return 0;
	Q.data[Q.rear] = x;//变量 x 入队
	Q.rear++;//队尾指针后移
	return 1;//入队成功
}

It is the pointer of the head of the team that goes out of the team to fight for, and needs to判断队空Q.front == Q.rear

int DeQueue(Queue& Q, int& x) {
    
    //出队操作
	if (Q.front == Q.rear)//若队空,则无法出队
		return 0;
	x = Q.data[Q.front];//变量 x 接收出队元素
	Q.front++;//队首指针后移
	return 1;//出队成功
}

circular queue

​Because Q.front == Q.rear judged that the team was empty before, if it loops, it means both empty and full, so it is possible, so that 牺牲一个空间Q.front == Q.rear can only be used to judge empty.

Empty :Q.front == Q.rear

Full verdict :(Q.rear + 1) % MaxSize == Q.front(If the rear is moved backward one is the front, it means it is full)

​ Both the tail pointer and the head pointer need to move backwards+1取余

//循环队列的入队和出队:(牺牲一个存储空间)
int EnQueue(Queue& Q, int x) {
    
    //入队操作
	if ((Q.rear + 1) % MaxSize == Q.front)//若队满,则无法入队
		return 0;
	Q.data[Q.rear] = x;//变量 x 入队
	Q.rear = (Q.rear + 1) % MaxSize;//队尾指针后移
	return 1;//入队成功
}
int DeQueue(Queue& Q, int& x) {
    
    //出队操作
	if (Q.front == Q.rear)//若队空,则无法出队
		return 0;
	x = Q.data[Q.front];//变量 x 接收出队元素
	Q.front = (Q.front + 1) % MaxSize;//队首指针后移
	return 1;//出队成功
}
04 If you want all the elements in the circular queue to be utilized, you need to set a flag field tag, and use the value of the tag to be 0 or 1 to distinguish that the queue status is "empty" when the queue head pointer front and the queue tail pointer rear are the same Still "full". Try to write enqueue and dequeue algorithms corresponding to this structure.
  1. In the circular queue, Q.front == Q.rear was originally able to judge whether the queue is empty or full, so a space is sacrificed above for special processing;
  2. This question judges whether the team is empty or full by setting the flag field;
  3. Here it is necessary to judge that the team is full only when entering the team, so the tag becomes 1 after each entry; it is necessary to judge that the team is empty only when leaving the team, so the tag becomes 0 after each leaving the team; because the team is empty The judgment of Q.front == Q.rear needs to be judged when the team is full. Therefore, when the pointers of the head and tail of the queue are not in the same place, this judgment will not be entered. The tag should be set to 0 initially.
  4. Q.front == Q.rear && Q.tag == 1 and Q.front == Q.rear && Q.tag == 0 are very strong, both of which require two conditions to be met at the same time
typedef struct {
    
    
	int data[MaxSize];
	int front, rear;
	int tag;
}Queue;
void InitQueue(Queue& Q) {
    
    //初始化队列
	Q.front = 0;
	Q.rear = 0;
    Q.tag = 0;
}
int EnQueue(Queue& Q, int x) {
    
    
	if (Q.front == Q.rear && Q.tag == 1) {
    
    //若队满,则无法进行入队操作
		return 0;
	}
	Q.data[Q.rear] = x;
	Q.rear = (Q.rear + 1) % MaxSize;//队尾指针后移
	Q.tag = 1;//入队后可能会出现队满的情况,所以将 tag 标志域置为 1
	return 1;
}
int DeQueue(Queue& Q, int& x) {
    
    
	if (Q.front == Q.rear && Q.tag == 0) {
    
    
		return 0;//队空
	}
	x = Q.data[Q.front];
	Q.front = (Q.front + 1) % MaxSize;
	Q.tag == 0;//出队后可能会出现队空的情况,所以将 tag 标志域置为 0
	return 1;
}
05 Q is a queue, and S is an empty stack, which realizes the algorithm of reversing the elements in the queue.
  1. The queue is first-in-first-out, and the stack is last-in-first-out. The elements in the queue must be reversed, so the elements of the queue can be dequeued into the stack one by one. When the queue is empty, then pop out and enter the queue to achieve inversion.
//Q 是一个队列,S 是一个空栈,实现将队列中的元素逆置的算法。
void Reverse(Queue& Q, Stack& S) {
    
    
	int x;
	while (!IsEmpty(Q)) {
    
    //出队列入栈
		DeQueue(Q, x);
		Push(S, x);
	}
	while (!IsEmpty(S)) {
    
    //出栈入队列
		Pop(S, x);
		EnQueue(Q, x);
	}
}

Guess you like

Origin blog.csdn.net/knighthood2001/article/details/132526687