Data structure (three)-stack and queue

One, the stack

1. The concept of stack

(1) A linear table that only allows insertion and deletion at one end. The end that allows insertion and deletion is called the top of the stack, and the other end that does not allow insertion and deletion is called the bottom of the stack. When there are no elements in the stack, it is called an empty stack.

2. Sequential stack

(1) Definition:

  • The sequential stack is the sequential storage representation of the stack.
  • In fact, the sequential stack refers to the use of a continuous storage unit as the storage space for stack elements, but it is implemented by borrowing a one-dimensional array in the C language.
  • Because the subscript of a one-dimensional array starts from 0, S.top <0 when the stack is empty, so the top pointer S.top == 1 when the stack is empty.

(2) Realization

#pragma once
//SeqStack.h

#include<cstdio>
#include<cstdlib>
#define initSize 20
#define increments 10
typedef int SElemType;
typedef struct {
	SElemType* elem;
	int maxSize, top;
}SeqStack;

void overflowProcess(SeqStack& S) {
	S.maxSize += increments;
	SElemType* newArray = (SElemType*)malloc(sizeof(S.maxSize));
	for (int i = 0; i <= S.top; i++) newArray[i] = S.elem[i];
	free(S.elem);
	S.elem = newArray;
}
bool getTop(SeqStack& S, SElemType& x) {
	if (S.top == -1) return false;
	x = S.elem[S.top];
	return true;
}
bool stackEmpty(SeqStack& S) {
	return S.top == -1;
}
bool stackFull(SeqStack& S) {
	return S.top == S.maxSize;
}
int stackSize(SeqStack& S) {
	return S.top + 1;
}
bool Push(SeqStack& S, SElemType x) {
	if (stackFull(S)) overflowProcess(S);
	S.elem[++S.top] = x;
	return true;
}
bool Pop(SeqStack& S, SElemType& x) {
	if (S.top == -1)  return false;
	x = S.elem[S.top--];
	return true;
}
//SeqStack.cpp

#include "SeqStack.h"
void initStack(SeqStack& S) {
	S.elem = (SElemType*)malloc(initSize * sizeof(SElemType));
	S.maxSize = initSize;
	S.top = -1;
}

3. Dual stacks share the same stack space

(1) Features,

  • When two stacks are needed, a large enough stack space V[m] can be defined, and the two stacks can be set to stack 0 and stack 1.
  • The outer sides of the two ends of the space are respectively set as the bottom of the two stacks, denoted by b[0], b[1], so that the stack tops b[0] and b[1] of the two stacks are stretched toward the middle until When the tops of the two stacks meet, it is considered that an overflow has occurred.

(2) Realization

//DblStack.h

#pragma once
#include<cstdio>
#include<cstdlib>
#define m 20
typedef int SElemType;
typedef struct {
	int top[2], bot[2];
	SElemType V[m];
}DblStack;
//DblStack.cpp

#include "DblStack.h"
void initStack(DblStack& DS, SElemType x, int d) {
	DS.bot[0] = DS.top[0] = -1;
	DS.bot[1] = DS.top[1] = m;
}
bool Push(DblStack& DS, SElemType x, int d) {
	if (DS.top[0] + 1 == DS.top[1] || d != 0 && d != 1) return false;
	if (d == 0) DS.top[0]++;
	else DS.top[1]--;
	DS.V[DS.top[d]] = x;
	return true;
}
bool Pop(DblStack& DS, SElemType& x, int d) {
	if (d != 0 && d != 1 || DS.top[d] == DS.bot[d]) return false;
	x = DS.V[DS.top[d]];
	if (d == 0) DS.top[0]--;
	else DS.top[1]++;
	return true;
}

(3) Question:

  • If more stacks are required to share the same stack space, the use of sequential storage will make the processing very complicated.
  • The solution is to use the link method as the storage representation of the stack.

3. Chain stack

(1) Features

  • A chained stack is a linked storage representation of the stack. A chain stack is used to represent a stack, which represents the insertion and deletion of nodes.
  • When multiple stacks are used in the program at the same time, the use of link representation can not only improve efficiency, but also achieve the purpose of sharing storage space.
//LinkStack.h

#pragma once
#include<cstdio>
#include<cstdlib>
using namespace std;
typedef int SElemType;
typedef struct node {
	SElemType data;
	struct node* link;
}LinkNode, *LinkStack;
//LinkStack.cpp

#include "LinkStack.h"
void initStack(LinkStack& S) {
	S = NULL;
}
void clearStack(LinkStack& S) {
	LinkNode* p;
	while (S != NULL) {
		p = S; S = S->link; free(p);
	}
}
bool stackEmpty(LinkStack& S) {
	return S == NULL;
}
bool Push(LinkStack& S, SElemType x) {
	LinkNode* p = (LinkNode*)malloc(sizeof(LinkNode));
	p->data = x;
	p->link = S; S = p; return true;
}
bool Pop(LinkStack& S, SElemType& x) {
	if (S == NULL) return false;
	x = S->data;
	LinkNode* p = S;
	S = S->link;
	free(p);
	return true;
}
bool getTop(LinkStack& S, SElemType& x) {
	if (S == NULL) return false;
	x = S->data;
	return true;
}
int StackSize(LinkStack& S) {
	int sz = 0;
	LinkNode* p = S;
	while (p != NULL) {
		p = p->link;
		sz++;
	}
	return sz;
}

4. Use the stack and queue to determine whether a character sequence is a palindrome

In fact, the data type should be defined as char first.

#include<cstring>
#include "SeqStack.cpp"
#include "CircQueue.cpp"
bool ok(char* str) {
	SeqStack S;
	initStack(S);
	CircQueue Q;
	initQueue(Q);
	int ch1, ch2;
	for (int i = 0; i < strlen(str); i++) {
		enQueue(Q, str[i]);
		Push(S, str[i]);
	}
	while (!stackEmpty(S) && !queueEmpty(Q)) {
		Pop(S, ch1);
		deQueue(Q, ch2);
		if (ch1 != ch2) return false;
	}
	return true;

}

 

Second, the queue

1. Circular queue

//CircQueue.h

#pragma once

#include<cstdio>
#include<cstdlib>
#define queSize 30
typedef int QElemType;
typedef struct {
	QElemType elem[queSize];
	int front, rear;
}CircQueue;
//CircQueue.cpp

#include "CircQueue.h"
void initQueue(CircQueue& Q) {
	Q.front = 0;
	Q.rear = 0;
}
bool queueEmpty(CircQueue& Q) {
	return Q.front == Q.rear;
}
bool queueFull(CircQueue& Q) {
	return (Q.rear + 1) % queSize == Q.front;
}
int queueSize(CircQueue& Q) {
	return (Q.rear - Q.front + queSize) % queSize;
}
bool enQueue(CircQueue& Q, QElemType x) {
	if (queueFull(Q)) return false;
	Q.elem[Q.rear] = x;
	Q.rear = (Q.rear + 1) % queSize;
	return true;
}
bool deQueue(CircQueue& Q, QElemType& x) {
	if (queueEmpty(Q)) return false;
	x = Q.elem[Q.front];
	Q.front = (Q.front + 1) % queSize;
	return true;
}
bool getFront(CircQueue& Q, QElemType& x) {
	if (queueEmpty(Q)) return false;
	x = Q.elem[Q.front];
	return true;
}

2. Chained queue

(1) I really want to complain about this. First of all, this chained queue is designed to be almost the same as a linked list. Secondly, this Q.rear can be said to have no effect. Because the judgment at the end of the line is Q.front == NULL.

//LinkQueue.h

#pragma once
#include<cstdio>
#include<cstdlib>
using namespace std;
typedef int QElemType;
typedef struct Node {
	QElemType data;
	struct Node* link;
}LinkNode;
typedef struct {
	LinkNode* front, * rear;
}LinkQueue;
//LinkQueue.cpp

#include "LinkQueue.h"
void initQueue(LinkQueue& Q) {
	Q.front = Q.rear = NULL;
}
void ClearQueue(LinkQueue& Q) {
	LinkNode* p;
	while (Q.front != NULL) {
		p = Q.front;
		Q.front = p->link;
		free(p);
	}
	Q.rear = NULL;
}
bool QueueEmpty(LinkQueue& Q) {
	return Q.front == NULL;
}
bool enQueue(LinkQueue& Q, QElemType x) {
	LinkNode* p = (LinkNode*)malloc(sizeof(LinkNode));
	p->data = x;
	if (Q.front == NULL) { Q.front = Q.rear = p; }
	else { Q.rear = p; }
	return true;
}
bool deQueue(LinkQueue& Q, QElemType &x) {
	if (Q.front == NULL) return false;
	LinkNode* p = Q.front;
	x = p->data;
	Q.front = Q.front->link;
	free(p);
	if (Q.front = NULL) Q.rear = NULL;
	return true;
}
bool getFront(LinkQueue& Q, QElemType& x) {
	if (Q.front == NULL) return false;
	x = Q.front->data; return true;
}
int QueueSize(LinkQueue& Q) {
	LinkNode* p = Q.front;
	int sz = 0;
	while (p != NULL) {
		p = p->link;
		sz++;
	}
	return sz;
}

Third, the application of the stack

1. Number system conversion

#include "LinkStack.cpp"
int BaseTrans(int N, int k) {
	int i;
	long result = 0;
	LinkStack S;
	initStack(S);
	while (N != 0) {
		i = N % k;
		N /= k;
		Push(S, i);
	}
	while (!stackEmpty(S)) {
		Pop(S, i);
		result = result * 10 + (long)i;
	}
	return result;
}
void main(void) {
	int N, k;
	printf("请输入一个十进制非负整数:\n");
	scanf("%d", &N);
	printf("要转换为多少进制的数:\n");
	scanf("%d", &k);
	printf("%d转换为%d进制数为%d\n", N, k, BaseTrans(N, k));
}

2. Bracket matching

#include "LinkStack.cpp"
void brachetMatch(char expr[]) {
	LinkStack S;
	initStack(S);
	int j, i = 0;
	char ch = expr[i];
	while (ch != '\0') {
		if (ch == '(') Push(S, i);
		else if (ch == ')') {
			if (!stackEmpty(S)) {
				Pop(S, j);
				printf("位置%d的'('与位置%d的')'匹配\n", j, i);
			}
			else printf("没有与位置%d的')'匹配的'('\n", i);
		}
		ch = expr[++i];
	}
	while (!stackEmpty(S)) {
		Pop(S, j);
		printf("没有与位置%d的'('匹配的')'!\n", j);
	}
}
int main(void) {
	char A[] = "(a*(b+c)-d)\0";
	char B[] = "(a+b))(\0";
	printf("%s\n", A);
	brachetMatch(A);
	printf("%s", B);
	brachetMatch(B);
	return 0;
}

3. The suffix indicates the value of the calculation expression

#include<cmath>
#include<cstdio>
#include<cstdlib>
using namespace std;
#define stkSize 20
bool DoOperator(double OPEN[], int& top, char op) {
	double left, right;
	if (top == -1) {
		printf("缺少右操作数!\n");
		return false;
	}
	right = OPEN[top--];
	if (top == -1) {
		printf("缺少左操作数!\n");
		return false;
	}
	left = OPEN[top--];
	switch (op) {
	case'+': OPEN[++top] = left + right; break;
	case'-': OPEN[++top] = left - right; break;
	case'*': OPEN[++top] = left * right; break;
	case'/': 
		if (fabs(right) < 1e-6) {
			printf("Divide by zero!\n");
			return false;
		}
		else {
			OPEN[++top] = left / right;
			break;
		}
	default: return false;
	}
	return true;
}
int main() {
	char A[] = "5964-*+93/-#";
	double OPEN[stkSize], result;
	int i = 0, top = -1;
	char ch = A[i++];
	while (ch != '#') {
		if (ch >= '0' && ch <= '9') OPEN[++top] = (double)(ch - 48);
		else if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {
			if (!DoOperator(OPEN, top, ch)) {
				printf("运行出错!\n");
				exit(1);
			}
		}
		else printf("输入了非法字符,请重新输入!\n");
		ch = A[i++];
	}
	result = OPEN[top--];
	printf("计算结果是:%g\n", result);
	return 0;
}

4. Infix representation is converted to suffix representation

 

 

Five, recursion

Six, deque

//SeqDeque.h

#pragma once
#include<cstdio>
#define maxSize 100
typedef int DQElemType;
typedef struct {
	DQElemType elem[maxSize];
	int end1, end2;
}SeqDeque;
//SeqDeque.cpp

#include "SeqDeque.h"
bool enQueueHead(SeqDeque& Q, DQElemType x) {
	if ((Q.end2 + 1) % maxSize == Q.end1) return false;
	Q.end1 = (Q.end1 - 1 + maxSize) % maxSize;
	Q.elem[Q.end1] = x;
	return true;
}
bool deQueueHead(SeqDeque& Q, DQElemType& x) {
	if (Q.end1 == Q.end2) return false;
	x = Q.elem[Q.end1];
	Q.end1 = (Q.end1 + 1) % maxSize;
	return true;
}
bool getHead(SeqDeque& Q, DQElemType& x) {
	if (Q.end1 == Q.end2) return false;
	x = Q.elem[Q.end1];
	return true;
}
bool enQueueTail(SeqDeque& Q, DQElemType x) {
	if ((Q.end1 + 1) % maxSize == Q.end1) return false;
	Q.elem[Q.end2] = x;
	Q.end2 = (Q.end2 + 1) % maxSize;
	return true;
}
bool deQueueTail(SeqDeque& Q, DQElemType& x) {
	if (Q.end1 == Q.end2) return false;
	Q.end2 = (Q.end2 - 1 + maxSize) % maxSize;
	x = Q.elem[Q.end2];
	return true;
}

Seven, priority queue

//PriorityQueue.h

#pragma once
#include<cstdio>
#include<cstdlib>
using namespace std;
#define maxPQSize 50
typedef int PQElemType;
typedef struct {
	PQElemType elem[maxPQSize];
	int n;
}PQueue;
//PriorityQueue.cpp

#include "PriorityQueue.h"
bool PQInsert(PQueue& PQ, PQElemType x) {
	if (PQ.n == maxPQSize) return false;
	PQ.elem[PQ.n++] = x;
	return true;
}
bool PQRemove(PQueue& PQ, PQElemType& x) {
	//这里作者又在搞事情,规定数值最小的优先级最大。但是在STL中默认情况下明明是数值越大优先级越高。
	if (PQ.n == 0) return false;
	PQElemType min = PQ.elem[0];
	int k = 0;
	for (int i = 1; i < PQ.n; i++) {
		if (min < PQ.elem[i]) {
			k = i;
			min = PQ.elem[i];
		}
	}
	x = PQ.elem[k];
	PQ.n--;
	PQ.elem[k] = PQ.elem[PQ.n];
	return true;
}

 

Guess you like

Origin blog.csdn.net/qq_45812711/article/details/105782626