数据结构-栈和队列

定义:栈是一种只能在一端进行插入或删除操作的线性表。
栈顶:允许进行插入、删除操作的一端。
栈底:表的另一端。
空栈:栈中没有数据元素。
进栈/入栈:栈的插入操作。
退栈/出栈:栈的删除操作。
主要特点:后进先出。

栈的顺序存储结构及其基本运算实现

假设栈元素最大不超过MaxSize,所有元素都具有同一数据类型ElemType
定义顺序栈

typedef struct
{	ElemType data[MaxSize];
	int top;//栈顶指针
}SqStack;

总结:
约定top总指向栈顶元素,初始值为-1
当top=MaxSize-1时不能再进栈
进栈top+1,出栈top-1

顺序栈4要素:
栈空条件:top=-1
栈满条件:top=MaxSize-1
进栈e操作:top++,将e放在top处
退栈操作:从top处取出元素e,top–
1、初始化栈InitStack(&s)

void InitStack(SqStack *&s)
{	s=(SqStack *)malloc(sizeof(SqStack));
	s->top=-1;
}

2、销毁栈DestroyStack(&s)

void DestroyStack(SqStack *&s)
{	free(s);
}

3、判断栈是否为空StackEmpty(s)

bool StackEmpty(SqStack *s)
{
	return(s->top==-1);
}

4、进栈Push(&s,e)

bool Push(SqStack *&s,ElemType e)
{	if(s->top==MaxSize-1)
		return False;
	s->top++;
	s->data[s->top]=e;
	return true;
}

5、出栈Pop(&s,&e)

bool Pop(SqStack *&s,ElemType &e)
{	if(s->top==-1)
		return false;
	e=s->data[s->top];
	s->top--;
	return true;
}

6、取栈顶元素GetTop(s,&e)

bool GetTop(SqStack *s,ElemType &e)
{	
	if(s->top==-1)
		return false;
		e=s->data[s->top];
		return true;
}

链栈

数据节点定义如下:

typedef struct linknode
{	ElemType data;
	struct linknode *next;
}LiStack;

1、初始化栈InitStack(&s)

void InitStack(LiStack *&s)
{	s=(LiStack *)malloc(sizeof(LiStack));
	s->next=NULL;
}

2、销毁栈DestroyStack(&s)

{	LiStack *p=s,*q=s->next;
	while(q!=NULL)
	{	free(p);
		p=q;
		q=p->next;
	}
	free(p);
}

3、判断栈是否为空StackEmpty(s)

bool StackEmpty(LiStack *s)
{
	return(s->next==NULL);
}

4、进栈Push(&s,e)

void Push(LiStack *&s,ElemType e)
{	LiStack *p;
	p=(LiStack *)malloc(sizeof(LiStack));
	p->data=e;
	p->next=s->next;
	s->next=p;
}

5、出栈Pop(&s,&e)

bool Pop(LiStack *&s,ElemType &e)
{	LiStack *p;
	if(s->next==NULL)
		return false;
	p=s->next;
	e=p->datal
	s->next=p->next;
	free(p);
	return true;
}

6、取栈顶元素GetTop(s,e)

bool GetTop(LiStack *s,ElemType &e)
{	if(s->next==NULL)
		return false;
	e=s->next->data;
	return true;
}

队列

定义:队列只能选取一个端点进行插入操作,另一个端点进行删除操作

概念:
队尾:进行插入的一端
队首/队头:进行删除的一端
进队/入队:向队列中插入新元素,新元素进队后就成为新的队尾元素
出队/离队:元素出队后,其后继元素就成为队首元素

主要特点:先进先出

队列的顺序存储结构及其基本运算的实现

顺序队类型SqQueue定义如下:

typedef struct
{	ElemType data[MaxSize];
	int front,rear;//队首和队尾指针
}SqQueue;

总结:约定rear总是指向队尾元素
元素进队,rear增1
约定front指向当前队中队头元素的前一位置
元素出队,front增1
当rear=MaxSize-1时不能再进队

顺序队4要素:
队空条件:front=rear
队满条件:rear=MaxSize-1
元素e进队:rear++;data[rear]=e;
元素e出队:front++;e=data[front];

缺点:当队满条件为真时,队中可能还有若干空位置。
这种溢出并不是真正的溢出,称为假溢出。
1、初始化队列

void InitQueue(SqQueue *&q)
{	q=(SqQueue *)malloc(sizeof(SqQueue));
	q->front=q->rear=-1;
}

2、销毁队列

void DestroyQueue(SqQueue *&q)
{	
	free(q);
}

3、判断队列是否为空

bool QueueEmpty(SqQueue *q)
{
	return(q->front==q->rear);
}

4、进队列

bool enQueue(SqQueue *&q,ElemType e)
{	if(q->rear==MaxSize-1)
		return false;
	q->rear++;
	q->data[q->rear]=e;
	return true;
}

5、出队列

bool deQueue(SqQueue *&q,ElemType &e)
{	if(q->front==q->rear)
		return false;
	q->front++;
	e=q->data[q->front];
	return true;
}

环形队列

4要素:
1、队空条件:front=rear
2、队满条件:(rear+1)%MaxSize=front
3、进队e操作:rear=(rear+1)%MaxSize;
4、出队操作:front=(front+1)%MaxSize

1、已知front、rear,求队中元素个数count:
count=(rear-front+MaxSize)%MaxSize
2、已知front、count,求rear:
rear=(front+count)%MaxSize
3、已知rear、count,求front:
front=(rear-count+MaxSize)%MaxSize

环形队列类型:

typedef struct
{	ElemType data[MaxSize];
	int front;  //队头指针
	int count;  //队列中元素个数
}QuType;

进队运算算法

bool EnQueue(QuType *&qu,ElemType x)
{	int rear;   //临时队尾指针
	if(qu->count==MaxSize)
		return false;
	else{
	rear=(qu->front+qu->count)%MaxSize;
	rear=(rear+1)%MaxSize;//队尾循环增1
	qu->data[rear]=x;
	qu->count++;
	return true;
	}
}

出队运算算法:

bool DeQueue(QuType *&qu,ElemType &x)
{	if(qu->count==0)
		return false;
	else{
	qu->front=(qu->front+1)%MaxSize;
	x=qu->data[qu->front];
	qu->count--;
	return true;
	}
}

比较:
1、环形队列比非环形队列更有效利用内存空间,即环形队列会重复使用已经出队元素的空间,不会出现假溢出。
2、如果算法中需要使用所有进队元素来进一步求解,此时可以使用非环形队列。

链队

定义:采用链表存储的队列,采用不带头节点的单链表实现。
组成:1、存储队列元素的单链表节点
2、指向队头和队尾指针的链队头节点

单链表中数据节点类型QNode

typedef struct qnode
{	ElemType data;//数据元素
	struct qnode *next;
}QNode;

链队中头节点类型LiQueue

typedef struct
{	QNode *front;
	QNode *rear;
}LiQueue;

链队4要素:
1、队空条件:front=rear=NULL
2、队满条件:不考虑
3、进队e操作:将包含e的节点插入到单链表表尾
4、出队操作:删除单链表首数据节点

链队的存储结构及其基本运算的实现

1、初始化队列

void InitQueue(LiQueue *&q)
{	q=(LiQueue *)malloc(sizeof(LiQueue));//即只创建一个链队头节点
	q->front=q->rear=NULL;
}

2、销毁队列

void DestroyQueue(LiQueue *&q)
{	QNode *p=q->front,*r;
	if(p!-NULL)
	{	r=p->next;
		while(r!=NULL)
		{	free(p);
			p=r;r=p->next;
		}
	}
    free(p);free(q);
}

3、判断队列是否为空

bool QueueEmpty(LiQueue *q)
{
	return(q->rear==NULL);
}

4、进队

void enQueue(LiQueue *&q,ElemType e)
{	QNode *p;
	p=(QNode *)malloc(sizeof(QNode));
	p->data=e;
	p->next-NULL;
	if(q->rear==NULL)//若链队为空,新节点是队首节点又是队尾节点
		q->front=q->rear=p;
	else
	{	q->rear->next=p;//将p节点链到队尾,并将rear指向它
		q->rear=p;
	}
}

5、出队

void deQueue(LiQueue *&q,ElemType &e)
{	QNode *t;
	if(q->rear==NULL) return false;
	t=q->front;
	if(q->front==q->rear)
		q->front=q->rear=NULL;
	else
	q->front=q->front->next;
	e=t->data;
	free(t);
	return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值