数据结构——第二讲、线性结构(堆栈和队列)

2.2 堆栈

  堆栈和队列都是对线性表做一些特殊的限制,形成了两种存储数据的结构,一个是先进后出、一个是先进先出、可以解决实际生活中遇到的一些问题,数据库也可以理解成一种数据结构,只不过这种结构比较普通罢了。
2.2.1 什么是堆栈
先进后出,后进先出的线性表就是堆栈,相当于对线性表的操作做一些特殊的限制

  • 计算机计算表达式求值:后缀表达式(运算符号在运算数的后面,从左往右扫描,逐个的处理运算数和运算符号)。遇到运算数存下来,遇到符号就取出之前存的两个数字做运算,完成之后再存回去,最后弹出结果。

堆栈: 有一定操作限制的线性表,只在一端做插入、删除。
数据对象集: 一个有0个或多个元素的有穷线性表
操作集:

Stack CreateStack(int MaxSize);        //生成空堆栈,长度为MaxSize();
int IsFull(Stack s, int MaxSize);      //判断堆栈s是否已满。
void Push(Stack s, ElementType item);  //把元素item压入堆栈.
int IsEmpty(Stack s);                  //判断堆栈是否为空。
ElementType Pop(Stack s);              //删除栈顶元素,并返回新的栈顶元素

2.2.2 堆栈的顺序存储
用数组存储,最后一个元素的下标即为top,空栈时top为-1。

#define MaxSize <存储数据元素的最大个数>
typedef struct SNode *Stack;
struct SNode{
	ElementType Data[MaxSize];
	int top;
};
  • 压栈
void Push(Stack s, ElementType x){
	if(s->top == MaxSize-1){
		printf("堆栈满!");
	}else{
		top++;
		s->Data[s->top] = x;
	}
	return;
}
  • 出栈
ElementType Pop(Stack s){
	ElementType x;
	if(s->top == -1){
		printf("栈空!");
		return ERROR;
		}
	else{
			//如果不设置局部变量,可用:return s->Data[(s->top)--];
			x = s->Data[s->top];
			s->top--;
			return x;
		}
}

用一个数组存储两个堆栈,让堆栈从两边向中间生长。

typedef struct DSNode *DStack
struct DSNode{
	ElementType Data[MaxSize];
	int top1 = -1;
	int top2 = MaxSize;
};
  • 入栈
//Tag用来区分这两个堆栈,0表示第一个,1表示第二个。
void Push(DStack s, ElementType x, Tag i){
	if((s->top2 - s->top1) == 1){
		printf("栈满!");
		return ERROR;
	}else{
		if(!Tag)
			s->Data[++(s->top1)] = x;
		else
			s->Data[--(s->top2)] = x;
		return;
	}
}
  • 出栈
ElementType Pop(DStack s, int Tag){
	if(!Tag){
		if(s->top1 == -1){
			printf("空栈!");
			return ERROR;
		}else return s->Data[(s->top1)--];
	}else{
		if(s->top2 == MaxSize){
			printf("空栈!");
			return ERROR;
		}else return s->Data[(s->top2)++];
	}
}

2.2.3 堆栈的链式存储
  用单向链表实现堆栈,只能在链头操作(一个链表节点不知道它的上一个节点在哪里)

typedef struct SNode *Stack;
struct SNode{
	ElementType Data;
	Stack NEXT;
};
  • 创建一个空栈
//这个头结点不代表任何元素,一直存在在堆栈头,只是为了方便堆栈的插入删除操作。
Stack CreateStack(){
	Stack s = (Stack)malloc(sizeof(struct SNode));
	S->NEXT = NULL;
	return s;
}
//可以通过判断头结点的NEXT是否为NULL来得知是否为空。
int IsEmpty(Stack s){//为空返回1,不空返回0
	if(s->NEXT == NULL)
		return 1;
	else
		return 0;
}
  • 入栈
void Push(ElementType x, Stack s){
	Stack p = (Stack)malloc(sizeof(struct SNode));
	p->Data = x;
	p->NEXT = s->NEXT;
	s->NEXT = p;
}
  • 出栈
Stack Pop(Stack s){
	if(IsEmpty(s)){
		printf("空栈!");
		return NULL;
	}else{
		Stack p = s->NEXT;
		s->NEXT = p->NEXT;
		free(p);
		return s->NEXT;
	}
}

2.2.4 堆栈应用:表达式求值
中缀表达式转换为后缀表达式:
运算数:直接输出
左括号:压栈
右括号:出栈,直到遇到左括号
运算符:遇到运算符号先入栈,直到遇到比栈顶符号优先级低的,出栈,然后该符号再和下一个栈顶元素比较,直到比栈顶高级或空栈。
后缀表达式求值:
运算数:入栈
运算符:弹出合适数量的运算数做计算

2.3 队列

  插入(入队AddQ)和删除(出队DeleteQ)位于队列两头。
类型名称: 队列(Queue)
数据对象集: 一个有0个或多个元素的有穷线性表。
操作集:

Queue CreateQueue(int MaxSize);
int IsFull(Queue Q, int MaxSize);
void AddQ(Queue Q, ElementType x);
int IsEmpty(Queue Q);
ElementTpye DeleteQ(Queue Q);

队列的顺序存储实现

#define MaxSize<队列的最大个数>
typedef struct QNode *Queue;
struct QNode{
	ElementType Data[MaxSize];
	front;//队列头
	rear;//队列尾
};
  • 入队
void AddQ(Queue Q, ElementType x){
	if((Q->rear+1)%MaxSize == Q->front){
		printf("队列满");
		return;
	}
	Q->rear = (Q->rear+1)%MaxSize;
	Q->Data[Q->rear] = x;
}
  • 出队
ElementType DeleteQ(Queue Q){
	if(Q->rear == Q->front){
		printf("队列空");
		return NULL;
	}
	Q->front = (Q->front+1)%MaxSize;
	return Q->Data[Q->front];
}

队列的链式存储
  front设在链表头,rear设在链表尾

typedef struct Node *List
struct Node{
	ElementType Data;
	List NEXT;
};
struct QNode{
	List front;
	List rear;
};
typedef struct QNode *Queue//一个QNode类型的指针,不同的指针表示不同的队列。
  • 入队
void AddQ(Queue Q, ElementType x){
	List s = (List)malloc(sizeof(struct Node));
	s->Data = x;
	s->NEXT = NULL;
	if(Q->rear == NULL){
		Q->rear = s;
		return;
	}
	Q->rear->NEXT = s;
	Q->rear = s;
	return;
}
  • 出队
ElementType DeleteQ(Queue Q){
	if(Q->front == NULL){
		printf("栈空!");
		return NULL;
	}
	//如果只有一个元素,就把rear和front都置为NULL
	if(Q->rear == Q->front)Q->rear = NULL;
	List s = Q->front;
	ElementType x = s->Data;
	//如果只有一个元素那么s的NEXT就是NULL,这里使用小技巧同时涵盖了一个或多个元素的情况
	Q->front = s->NEXT;
	free(s);
	return x;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值