数据机构之队列和栈

栈和队列

一、栈和队列的概念

1、栈的概念

栈是只允许在一端进行插入或者删除操作的线性表。

栈还涉及一些概念:

栈顶: 线性表允许插入和删除元素的一端。

栈底: 固定的,不允许进行插入和删除的一端。

栈的输入输出特点是FILO(first in last out)后进先出,假如栈中有四个元素a_1,a_2,a_3,a_4已经全部按顺序入栈,则出栈的顺序是a_4,a_3,a_2,a_1。

这里写图片描述

2、栈的基本操作

栈的基本操作包括出栈,入栈,获取栈顶元素等:

  • InitStack(&S) 初始化操作
  • StackEmpty(S) 栈的判空
  • Push(&S, x) 入栈
  • Pop(&s, &x) 出栈
  • GetTop(S, &x) 获取栈顶元素
  • ClearStack(&S) 清空栈

3、队列的概念

队列也是一种操作受限的线性表,只允许在一端进行插入操作,另一端进行删除操作。和栈相反队列是FIFO(First In First Out)先入先出。

出队:队头元素被删除;

入队:队尾元素被插入到队列中。

栈的输入输出特点是FILO(first in last out)后进先出,假如栈中有四个元素a_1,a_2,a_3,a_4已经全部按顺序入栈,则出栈的顺序是a_1,a_2,a_3,a_4。

这里写图片描述

4、队列的基本操作

队列的基本操作有出队入队等

  • InitQueue(&Q) 初始化队列
  • QueueEmpty(Q) 队列判空
  • EnQueue(&Q, x) 入队
  • DeQueue(&Q, &x) 出队
  • GetHead(Q, &x) 获取对头元素

二、栈和队列的结构定义

栈,队列和线性表相同可分为顺序和链式。

1、栈

栈可分为顺序栈和链式栈,顺序栈按照之前线性表的分类可以分为动态内存分配和静态内存分配。

静态顺序栈

    #define MAX_SIZE 100
    typedef int ElemType;
    typedef struct
    {
    	int top, base;
      	ElemType data[MAX_SIZE];
    }sqStack;

动态顺序栈

    #define INIT_SIZE 100
    #define INCREASE_SIZE 20
    typedef int ElemType;
    typedef struct
    {
    	ElemType* base;
      	ElemType* top;
        int stackSize; 
    }sqStack;

链式栈

    typedef int ElemType;
    typedef struct StackNode
    {
    	struct StackNode* next;
      	ElemType data;
    }StackNode,* LinkStack;

2、队列

队列的分类相对于栈来说更多,包含顺序队列,循环队列,链式队列,双端队列,其中双端队列可以看成栈和队列的结合。

顺序队列

    #define MAX_SIZE 100
    typedef int ElemType;
    typedef struct
    {
    	ElemType data[MAX_SIZE];
      	int front, rear;
    }sqQueue;

循环队列

循环队列的定义和顺序队列相同,只是操作方法不同,队列入队出队操作过程中,当队尾队尾已经抵达已分配空间的末端时,就无法在入队,但是由于之前的出队操作,队头之前的数据空间已经不再使用,就意味着队列并未真正意义上的满,因此将指针再定位回之前释放的空间加以利用。

需要说的是假若以Q.rear == Q.front判断队列满就会发生和判空相冲突,因此回退一个空间作为判断的方式:(Q.rear + 1)%MAX_SIZE = Q.front;除余是为了避免Q.rear和Q.front一个在队尾,一个在队头的情况的发生。具体代码之后会说到。

链式队列

    typedef int ElemType;
    typedef struct QueueNode
    {
    	ElemType data;
      	struct QueueNode* next;
    }QueueNode,* LinkQueue;
    
    typedef struct
    {
    	LinkQueue front, rear;
    }Queue;

双端队列

队列是只允许一段入队,另一端出队的结构,而双端队列是允许在一端进行两种操作另一端进行一种操作的队列,分为:

输入受限双端队列:两端都可以出队,只有一端可以入队。

这里写图片描述

输出受限双端队列:两端都可以入队,只有一端可以出队。
这里写图片描述

三、具体代码

1、栈的相关操作

顺序栈入栈

    //function:		push a element into the stack
    //parameters:	S		the pointer of stack
    //				e		the element you would push into
    //return:		TRUE	successfully
    //				FALSE	failurely
    int Push(sqStack* S, Elemtype e)
    {
    	if(S->base == NULL)
    	{
    		return FALSE;
    	}
    	
    	if(S->stackSize == (S->top - S->base))
    	{
    		Elemtype* tmp = (Elemtype*)realloc(S->base, sizeof(Elemtype) * (S->stackSize + INCREASE_SIZE));
    		if(tmp == NULL)
    		{
    			return FALSE;
    		}
    		
    		S->base = tmp;
    		S->top = S->base + S->stackSize;
    		S->stackSize = S->stackSize + INCREASE_SIZE;
    	}
    	
    	*S->top++ = e;
    	return TRUE;
    }

顺序栈出栈

    //function:		pop a element from the top of stack
    //parameters:	S		the pointer of stack
    //				e		the pointer which would storage the data 
    //return:		TRUE	successfully
    //				FALSE	failurely
    int Pop(sqStack* S, Elemtype* e)
    {
    	if(S->base == NULL || (S->top - S->base) == 0)
    	{
    		return FALSE;
    	}
    	
    	*e = *(--S->top);
    	return TRUE;
    }

链式栈入栈

    //function:		push a element into the stack
    //parameters:	S		the pointer of stack
    //				e		the element you would push into
    //return:		TRUE	successfully
    //				FALSE	failurely
    int Push(LinkStack* S, Elemtype e)
    {
    	if(S == NULL)
        {
        	return FALSE;
        }
      	
      	StackNode ptr = (LinkNode)malloc(sizeof(StackNode));
      	ptr->data = e;
      	ptr->next = (*S)->next;
      	(*S)->next = ptr;
      	return TRUE;
    }

链式栈出栈

    //function:		pop a element from the top of stack
    //parameters:	S		the pointer of stack
    //				e		the pointer which would storage the data 
    //return:		TRUE	successfully
    //				FALSE	failurely
    int Pop(LinkStack* S, Elemtype* e)
    {
    	if(S == NULL && S->next == NULL)
        {
        	return FALSE;
        }
      	
      	LinkStack ptr = (*S)->next;
      	(*S)->next = ptr->next;
      	*e = ptr->data;
      	free(ptr);
      	ptr = NULL;
      	return TRUE;
    }

2、队列相关操作

顺序循环队列入队

    //function:		insert element into queue
    //parameters:	Q		the pointer that points to queue
    //				e 		the element you would insert
    //return:		TRUE	successfully
    //				FALSE	failurely
    int EnQueue(sqQueue* Q, ElemType e)
    {
    	if(QueueLength(*Q) == MAX_SIZE)
    	{
    		return FALSE;
    	}
    	
    	Q->data[Q->rear++] = e;
    	Q->rear = Q->rear % MAX_SIZE;
    	return TRUE;
    }

顺序循环队列出队

    //function:		delete element from queue
    //parameters:	Q		the pointer that points to queue
    //				e		storage the element you would delete
    //return:		TRUE	successfully
    //				FALSE	failurely
    int DeQueue(sqQueue* Q, ElemType* e)
    {
    	if(QueueEmpty(*Q))
    	{
    		return FALSE;
    	}
    	
    	*e = Q->data[Q->front++];
    	Q->front = Q->front % MAX_SIZE;
    	return TRUE;
    }

链式队列入队

    //function:		insert element into queue
    //parameters:	Q		the pointer that points to queue
    //				e 		the element you would insert
    //return:		TRUE	successfully
    //				FALSE	failurely
    int EnQueue(LinkQueue* Q, ElemType e)
    {
    	if(Q->rear == Q->front)
        {
        	return FALSE;
        }
      	
      	LinkQueue ptr = (LinkQueue)malloc(sizeof(QueueNode));
      	ptr->data = e;
      	ptr->next = NULL;
      	Q->rear->next = ptr;
      	Q->rear = ptr;
      	return TRUE;
    }

链式队列出队

    //function:		delete element from queue
    //parameters:	Q		the pointer that points to queue
    //				e		storage the element you would delete
    //return:		TRUE	successfully
    //				FALSE	failurely
    int DeQueue(LinkQueue* Q, ElemType* e)
    {
      	if(Q->rear == Q->front)
        {
        	return FALSE;
        }
      
      	LinkQueue ptr = Q->front;
      	Q->front = ptr->next;
      	*e = ptr->data;
      	free(ptr);
      	ptr = NULL;
      	return TRUE;
    }

相关代码的链接:http://download.csdn.net/detail/grayondream/9731257

数据结构算法在保研面试中通常是一个重要的考察内容。以下是一些建议和准备方法: 1. 熟悉常见的数据结构:掌握常见的数据结构,如数组、链表、队列、树、图等,并了解它们的特点和应用场景。 2. 理解常用算法:掌握常见的算法,如排序算法(如快速排序、归并排序)、查找算法(如二分查找)、图算法(如深度优先搜索、广度优先搜索)等。 3. 解决实际问题:通过解决一些实际问题来加深对数据结构算法的理解。可以尝试使用不同的数据结构算法来解决同一个问题,比较它们的效率和优缺点。 4. 刷题练习:刷题是提高数据结构算法能力的有效方法。可以选择一些经典的面试题目,如LeetCode上的题目,进行刷题练习。 5. 真题模拟:参加一些面试模拟或者做一些往年的保研面试真题,熟悉面试的形式和要求,提前了解可能会被问到的问题。 6. 思考优化方案:不仅要能够正确实现算法,还要思考如何优化算法的时间复杂度和空间复杂度,以及如何处理边界情况和异常情况。 7. 多思考背后原理:不仅要掌握并记住算法的实现细节,还要深入理解其背后的原理和思想,这样才能更好地应对面试中的问题。 记住,除了数据结构算法,面试官还可能问及其他相关的计算机基础知识,如操作系统、计算机网络、数据库等,所以综合准备是很重要的。祝你在保研面试中取得好成绩!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值