数据结构与算法学习(3)——栈和队列

目录

栈的基本概念

栈的输出序列

存储结构:顺序栈

存储结构:链栈

队列

 队列的顺序表示

链队列

应用(算法思路)

参考资料:


栈的基本概念

还有一个鲜明的例子:把栈想象成洗碗,只能在叠起来的碗的最高处拿或放(不过栈不能同时拿或放多个碗)

栈:限定仅在表尾(栈顶)进行插入或删除操作的线性表        表头(栈底)

        不含元素的空表称空栈

特点:先进后出(先进栈的后出栈)first in late out  (FILO)

           后进先出(后进栈的先出栈)late in first out  (LIFO)

逻辑结构:一对一

存储结构:顺序/链栈

栈的输出序列

举个例子:利用一个栈,如果输入序列由A,B,C组成。
通过栈可以实现如下输出:
A入,A出,B入,B出,C入,C出。(ABC)
A入,A出,B入,C入,C出,B出。(ACB)
A入,B入,B出,A出,C入,C出。(BAC)

那么问题来了:

利用一个栈,如果输入序列由A → B → C组成,试找出不可能实现的输出序列?(已经排除一个错误答案啦)

  1. B → A → C
  2. C → B → A
  3. C → A → B
  4. B → C → A  

答案是3.

存储结构:顺序栈

#define MaxSize 100
typedef struct
{
    int *base;        //栈底指针
    int *top;         //栈顶指针
    int stacksize;    //栈可用的最大容量
}SqStack;

//初始化
int InitStack( SqStack &s)
{
	s.base = new int [MaxSize];     // 申请存储空间
	if ( !s.base ) return  -1;

	s.top = s.base;		            // top初始为base,表示栈为空
	s.stacksize = MaxSize;	        // 最大容量
	return 1;
}

//入栈
int Push( SqStack &s, int e )
{
    if ( s.top – s.base >= s.stacksize )
          return -1;
    *s.top++ = e;                   // 从栈底开始录入,所以自增后置
    return 1;
}

//出栈
int Pop(SqStack &s, int &e )
{   
    if ( s.top == s.base )
           return -1;

    e = *--s.top;                   // 出栈前s.top指针指向的是空值
                                    // --s.top才是指向要出栈的值
    return 1;
}


 注:top 指向真正的栈顶元素之上的下标地址

         ps:要注意自增和自减的位置

存储结构:链栈

只能在链表头部进行操作,故没有必要附加头结点,栈顶指针就是链表的头指针。 

//结点定义
typedef struct StackNode
{
    int data;                    //数据域
    struct StackNode *next;      //指针域
} StackNode, *LinkStack;


//初始化
int InitStack(LinkStack &S )
{
	  S = NULL;
	  return 1;
}

//入栈
int Push ( LinkStack  &S, int e )
{  
    StackNode *p;
    p=new StackNode; 
    if ( !p ) return -1;         // 申请存储空间失败

    p -> data = e;
    p -> next = S;
    S = p;
    return 1;
}

//出栈
int Pop ( LinkStack &S, int &e)
{   
    StackNode *q;
    if ( S != NULL ) {
        q = S;		            // 以备释放结点
        e = S->data;
        S = S->next;
        delete q;		        // 释放结点
        return 1;
    }
    else
        return -1;
}



队列

(顾名思义,就是排队伍前面的出去,进来的排队伍后面)

定义:队列是限定只能在表的一端进行插入,在表的另一端进行删除的线性表

  • 队尾(rear)——允许插入的一端
  • 队头(front)——允许删除的一端

队列特点:先进先出(FIFO)

 除此之外,还有双端队列(同时具备栈和队列的特性)

 队列的顺序表示

实现方式:一维数组

#define MaxQSize 100
typedef struct
{
    int *base;        //存储空间
    int front;        //头指针
    int rear;         //尾指针
}SqQueue;

如下图,队列为空的条件为rear==front ,那么就会存在如下问题:

设数组大小为M,则:
当front=0,rear=M时,再有元素入队发生溢出——真溢出
当front\neq0,rear=M时,再有元素入队发生溢出——假溢出

于是,我们将队列设想成环形若rear+1==M,则令rear=0.

入队: sq[rear]=x;  rear=(rear+1)%M;    
出队: x=sq[front]; front=(front+1)%M;

 

以下是循环队列的部分代码

//初始化
int InitQueue( SqQueue &Q ) 
{
     Q.base = new int [MaxQSize];           // 申请空间
     if ( !Q.base )  return -1;		        //  存储分配失败

     Q.front = Q.rear = 0;			        //  头指针和尾指针置零
     return 1;
}

//入队
int EnQueue( SqQueue &Q, int e )
{  
   if ( ( (Q.rear+1) % MaxQSize ) == Q.front )
          return -1;
    else 
   {
          Q.base[Q.rear] = e;               // 在队尾插入
          Q.rear=(Q.rear+1) % MaxQSize;
          
          return 1;
    }
}

链队列

结点定义

typedef struct QNode
{
    int data;
    struct QNode *next;
} QNode, *QueuePtr;

typedef struct
{
    QueuePtr front;        //队头指针
    QueuePtr rear;         //队尾指针
}LinkQueue;

 以下是链队列的部分代码

//入队
int EnQueue( LinkQueue &Q,int e )
{   
    QueuePtr p;
    p= new QNode ;
    if ( !p ) return -1 ;  // 申请结点失败

    p->data = e;  
    p->next = NULL;
    Q.rear->next = p;      // 将新结点插入到队尾
    Q.rear = p;            // 修改队尾指针

    return 1;
}

//出队
int DeQueue(LinkQueue &Q, int &e ) 
{ 
   QueuePtr p;
   if( Q.front == Q.rear )  return  -1; // 队列为空

   p = Q.front->next;                   // p指向对头元素
   e = p->data; 
   Q.front->next = p->next;             // 修改头结点的指针
   if ( Q.rear ==  p ) 
       Q.rear = Q.front;              // 队列空时,队尾指针指向头结点
   delete p;
   return 1;
}

应用(算法思路)

放在社区学习活动(找不到就是我还没放)

参考资料:

1. 数据结构——使用C语言(第5版)

2. 数据结构——C++实现

3. 数据结构与算法 ppt(线性表)        张合生

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zedkyx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值