数据结构:栈和队列

五.栈与队列

栈定义:用来存储函数调用时各个函数的参数,返回地址及临时变量等。
特点:先进后出,不考虑排序。
队列特点:先进先出。
题目:用两个栈实现一个队列,队列申明如下,实现它的两个函数appendTail和deleteHead,即:队列的尾部插入节点,头部删除节点。

思路:自定义一个函数模板CQueue,它有public属性或方法:构造函数,析构函数,在尾部添加节点void appendTail(const T& node),删除队列的头节点T deleteHead().私有属性:stack<T> stack1;stack<T>stack2;由于定义CQueue,为模板的原因,在尾部添加节点实现函数为:template< typename T> void cQueue<T>::appendTail(const T& node){stack1.push(node)},删除队列头部的节点template<T> T cQueue<T> ::deleteHead()如果stack2<=0,当stack1.size()满足大于0时,将stack1,中的所有元素压入stack2.如果stack2==0,抛空。定义一个T类型的head并且赋初值为stack2.top,stack2.pop(),返回Head。

#include <iostream>  
#include <stack>  
#include <exception>  
using namespace std;  
  
template <typename T> class CQueue  
{  
public:  
    CQueue(void);  
    ~CQueue(void);  
  
    // 在队列末尾添加一个结点  
    void appendTail(const T& node);  
  
    // 删除队列的头结点  
    T deleteHead();  
  
private:  
    stack<T> stack1;  
    stack<T> stack2;  
};  
  
//成员函数定义.  
template <typename T>   
CQueue<T>::CQueue(void)  
{  
}  
  
template <typename T>   
CQueue<T>::~CQueue(void)  
{  
}  
  
//向队列中插入元素.  
template <typename T>   
void CQueue<T>::appendTail(const T& node)  
{  
    stack1.push(node);  
}  
  
//从队列中删除元素.  
template <typename T>   
T CQueue<T>::deleteHead()  
{  
    //先判断stack2是否为空.  
    //若其不为空,则从中弹出元素;  
    //若为空,则将stack1中元素依次弹出并存入stack2中.  
    if(stack2.size() <= 0)  
        while (stack1.size() > 0)  
        {//当stack2为空时,将stack1中所有元素存入stack2中.  
            T data = stack1.top();  
            stack1.pop();  
            stack2.push(data);  
        }  
        if(stack2.size() == 0)  
            throw new exception("queue is empty!");  
  
        T head = stack2.top();  
        stack2.pop();  
  
        return head;  
}  
  
//测试函数.  
void Test(char actual, char expected)  
{  
    if(actual == expected)  
        cout << "Test passed." << endl;  
    else  
        cout << "Test failed.\n" << endl;  
}  
  
int main()  
{  
    CQueue<char> queue;  
  
    queue.appendTail(‘a‘);  
    queue.appendTail(‘b‘);  
    queue.appendTail(‘c‘);  
  
    char head = queue.deleteHead();  
    Test(head, ‘a‘);  
  
    head = queue.deleteHead();  
    Test(head, ‘b‘);  
  
    queue.appendTail(‘d‘);  
    head = queue.deleteHead();  
    Test(head, ‘c‘);  
  
    queue.appendTail(‘e‘);  
    head = queue.deleteHead();  
    Test(head, ‘d‘);  
  
    head = queue.deleteHead();  
    Test(head, ‘e‘);  
  
    return 0;  
}  


总结:

栈:

#include <stdafx.h>
#include <stdio.h>
#include <iostream>
#include <stack>
using namespace std;
int main()
{
    stack<int> st;
    /*
        对栈的操作无非就是:验证是否为空、返回栈中元素数目、对栈顶元素删除、获取以及压入新元素
        st.empty();    验证是否为空
        st.size();    栈中元素个数
        st.pop();        删除栈顶元素,无返回值
        st.push();    将新元素压入栈中
        st.top();        返回栈顶元素

        st.size()为st对象调用stack类size函数
        st->size()针对于指针对象指向size函数
    */
    if(st.empty()){
        cout<<"stack is empty"<<endl;        
        cout<<"刚进行初始化stack的大小:  "<<st.size()<<endl;                //输出size
        st.push(111);
        st.push(222);                        //压入栈顶,必须是同类型的int值
        cout<<"push后的stack大小:  "<<st.size()<<endl;
        cout<<"取出stack顶元素:  "<<st.top()<<endl<<endl;
        //取出stack中所有元素
        while(st.size()>0){
            cout<<st.top()<<endl;
            st.pop();
            //因声明的是stack静态对象st,不用考虑内存泄漏
        }
        cout<<"stack size : "<<st.size()<<endl;
    }
    getchar();          //程序暂停等待用户输入任意字符,让命令行窗口不会一闪而过
    return 0;
}

队列:

#include <stdafx.h>
#include <stdio.h>
#include <iostream>
#include <queue>
using namespace std;
int main(){
    queue<int> p;
    /*
    q.empty()               如果队列为空
    q.size()                返回队列中元素的个数  
    q.pop()                 删除队列首元素无返回值
    q.front()               返回队首元素的值,但不删除该元素  
    q.push()                在队尾压入新元素  
    q.back()                返回队列尾元素的值,但不删除该元素  
    */
    if(p.empty()){
        cout<<"pop is empty"<<endl;        
        cout<<"刚进行初始化pop的大小:  "<<p.size()<<endl;                //输出size
        p.push(111);
        p.push(222);                        //压入栈顶,必须是同类型的int值
        cout<<"push后的pop大小:  "<<p.size()<<endl;
        cout<<"取出pop顶元素:  "<<p.front()<<endl<<endl;
        //取出pop中所有元素
        while(p.size()>0){
            cout<<p.front()<<endl;
            p.pop();
            //因声明的是pop静态对象p,不用考虑内存泄漏
        }
        cout<<"pop size : "<<p.size()<<endl;
    }
    getchar();
    return 0;
}

栈的数组实现  (利用栈的基本操作来实现对数组的操作)  栈:后进先出  数组:按 (索引->值) 依次存储

#include <stdafx.h>
#include <stdio.h>
#include <malloc.h>
#define maxsize 10
typedef struct        //定义结构体,并且在
{
    int data[maxsize];    //数组大小
    int top;            //栈顶坐标
    int base;        //栈底坐标
}seqstack;            //seqstack为结构体的别名而已,还可以使用多个别名,且多个别名创建的对象使用的不是同一个内存空间, 并根据数组的结构定义成员
seqstack * s;            //栈
void initstack(seqstack * s)
{
    s->top = 0;
    s->base = 0;
}
int empty(seqstack * s)
{
    if(s->top == s->base)
        return 1;
    else
        return 0;
}
//入栈:赋值 , 索引++
void  push(seqstack * s, int x)
{
    if(s->top >= maxsize-1)
    {
        printf("ERROR!\n");
    }
    else
    {
        s->data[s->top] = x;
        s->top++;
    }
}
//获取栈顶元素data[s->top--]  这里需要top--是因为入栈时top索引++了
void  pop(seqstack * s)
{
    if(empty(s))
    {
        printf("ERROR!\n");
    }
    else
    {
        s->top--;
        printf("%d\n",s->data[s->top]);
    }
}
int main()
{
    seqstack * s;
    //(seqstack *)强转,malloc(size)申请大小为size动态内存空间,sizeof(seqstack),seqstack类型占多少字节sizeof的值就是多大,如:sizeof(int) = 4
    s = (seqstack *)malloc(sizeof(seqstack));
    //此时s为空,s为指针对象,会以传址的方式将s传递给initstack函数
    initstack(s);
    push(s,1);
    push(s,3);
    pop(s);
    push(s,2);
    pop(s);
    pop(s);
    pop(s);
    return 0;
}

栈的链表实现        (利用栈的基本操作来实现对链表的操作)

#include <stdafx.h>
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
typedef struct node
{
    int data;
    struct node *next;
}node,linkstack;                    //使用多个别名,在这里node为节点
//初始化
void InitStack(linkstack * top)        
{
    top->next = NULL;
}
//是否为空   只用想想链表的结构就很清楚了,节点与节点之间通过指针关联,只要top->next为NULL即可
int IsEmpty(linkstack * top)
{
    if(top->next == NULL) return 1;
    return 0;
}
//入栈:新建一个节点赋值,让新节点的next指针指向NUll,栈内top->next指向新节点即可
int Push(linkstack * top, int x)
{
    node * p;    
    p = (node *)malloc(sizeof(node));
    if(p == NULL) return 0;
    p->data = x;
    p->next = top->next;            //top->next = null
    top->next = p;
    return 1;
}
//删除栈顶元素:
int Pop(linkstack * top, int *x)
{
    node * p;
    if(IsEmpty(top))
    {
        printf("ERROE!\n");
        return 0;
    }
    p = top->next;
    *x = p->data;
    top->next = p->next;
    free(p);
    return 1;
}
int main()
{
    int x;
    linkstack * s;
    s = (linkstack *)malloc(sizeof(linkstack));
    InitStack(s);
    Push(s,1);
    Push(s,3);
    Pop(s,&x);
    printf("%d\n",x);
    Push(s,2);
    Pop(s,&x);
    printf("%d\n",x);
    Pop(s,&x);
    printf("%d\n",x);
    Pop(s,&x);
    return 0;
}
#include <stdafx.h>
#include <stdio.h>
#include <malloc.h>
#define maxsize 66    //定义变量
typedef struct      //type define 结构定义
{
    int data[maxsize];
    int front,rear;   //front来记录列首,rear来记录列尾
}sequeue;
sequeue *q;          //循环链表
void initqueue(sequeue *q)
{
    q->front = -1;      //q指针指向sequeue对象中的front方法
    q->rear = -1;
}
int del(sequeue *q)     
{
    if(q->front == q->rear)      //列首列尾元素是否相等,若相等则是空的循环队列和数组
        return NULL;
    else
    {
        q->front++;          //->优先级比++大,故先执行->然后++
        return q->data[q->front];  //实现对数组的删除操作,没调用此方法一次就让front记录的值+1  
    }
}
int insertqueue(sequeue *q,int x)    //向队列中插入元素,思路:先判断列尾是否超出maxsize大小,然后让索引rear+1,对应的给数组data[rear+1]赋值,来实现插入
{
    if(q->rear >= maxsize-1)
        return NULL;
    else
    {
        (q->rear)++;            //列尾+1
        q->data[q->rear] = x;
        return 1;
    }
}
int empty(sequeue * q)          //简单判断队列是否为空,也就是数组data是否为空
{
    if(q->front == q->rear)
        return 0;
    else
        return 1;             //这里也可扩展,返回队列元素大小,前提是需要让rear递增
}
void print(sequeue * q)          //遍历输出数据元素
{
    if(q->front == q->rear)
        printf("ERROR!\n");
    else
    {
        while(empty(q))
        {
            q->front++;
            printf("%d\n",q->data[q->front]);
        }
    }
}
int main()
{
    int i;
    sequeue *q;
    q  = (sequeue *)malloc(sizeof(sequeue));
    initqueue(q);
    for(i = 0; i < 6; i++)
        insertqueue(q,i);
    printf("front is %d\n\n",del(q));
    printf("Then the last data is:\n");
    print(q);
    return 0;
}

队列的数组实现(利用数组的数据结构来对队列进行操作)   先想想数组的实现原理
原理:
front           ->            rear           (假设队列顺序从左往右)
data[front]  ->             data[rear] (如果对队列中front、rear操作,则相应的数据元素、大小也随之变化)
#include <stdafx.h>
#include <stdio.h>
#include <malloc.h>
#define maxsize 66    //定义变量
typedef struct      //type define 结构定义
{
    int data[maxsize];
    int front,rear;   //front来记录列首,rear来记录列尾
}sequeue;
sequeue *q;          //循环链表
void initqueue(sequeue *q)
{
    q->front = -1;      //q指针指向sequeue对象中的front方法
    q->rear = -1;
}
int del(sequeue *q)     
{
    if(q->front == q->rear)      //列首列尾元素是否相等,若相等则是空的循环队列和数组
        return NULL;
    else
    {
        q->front++;          //->优先级比++大,故先执行->然后++
        return q->data[q->front];  //实现对数组的删除操作,没调用此方法一次就让front记录的值+1  
    }
}
int insertqueue(sequeue *q,int x)    //向队列中插入元素,思路:先判断列尾是否超出maxsize大小,然后让索引rear+1,对应的给数组data[rear+1]赋值,来实现插入
{
    if(q->rear >= maxsize-1)
        return NULL;
    else
    {
        (q->rear)++;            //列尾+1
        q->data[q->rear] = x;
        return 1;
    }
}
int empty(sequeue * q)          //简单判断队列是否为空,也就是数组data是否为空
{
    if(q->front == q->rear)
        return 0;
    else
        return 1;             //这里也可扩展,返回队列元素大小,前提是需要让rear递增
}
void print(sequeue * q)          //遍历输出数据元素
{
    if(q->front == q->rear)
        printf("ERROR!\n");
    else
    {
        while(empty(q))
        {
            q->front++;
            printf("%d\n",q->data[q->front]);
        }
    }
}
int main()
{
    int i;
    sequeue *q;
    q  = (sequeue *)malloc(sizeof(sequeue));
    initqueue(q);
    for(i = 0; i < 6; i++)
        insertqueue(q,i);
    printf("front is %d\n\n",del(q));
    printf("Then the last data is:\n");
    print(q);
    return 0;
}

队列的链表实现  (利用链表的数据结构来实现对队列的操作)  先想想链表的实现原理,要知道链表中某个节点,那就必须要知道它上一个节点

节点: [值 | 指针] (指向下一个节点的内存地址)

front           ->            rear           (假设队列顺序从左往右)

#include <stdafx.h>
#include <stdio.h>
#include <malloc.h>
typedef struct node        //节点
{
    int data;            //值
    struct node * next;      //指针
}linklist;             //节点对象             
typedef struct
{
    linklist * front, * rear;  //定义结构对象的两个指针,front表示上一个节点,rear表示下一个节点
}linkqueue;              
linkqueue * q;           //链表         
//建立队列
void initqueue(linkqueue * q)
{
    q->front = (linkqueue *)malloc(sizeof(linklist));  //动态分配,初始化为0
    q->front->next = NULL;                  //将首节点中指向下一节点的指针置空
    q->rear = q->front;                    //队列首位
}
//判断队列空否
int empty(linkqueue * q)
{
    if(q->front == q->rear)
        return 1;
    else
        return 0;
}
//入队列     先定义一个与listlink相同的节点对象,然后再将它加入链表队列中(rear->next指向新建的节点)
void inqueue(linkqueue * q, int x)
{
    q->rear->next = (linklist *)malloc(sizeof(linklist));    //q->rear->next本来是NULL的,现在将对它赋予节点对象,也就连接了rear和rear->next
    q->rear->next->data = x;                    
    q->rear = q->rear->next;                    //让rear没有下一个节点
    q->rear->next = NULL;                       //确定操作的rear节点位于链尾
}
//出队列    从front节点开始一节一节的取,此方法每调用一个就取一个,一直取到最后一个时,就会一直返回q->rear
int outqueue(linkqueue * q)
{
    linklist * s;
    if(empty(q))
        return NULL;
    else
    {
        s = q->front->next;
        printf("%d\n",s->data);
        if(s == q->rear)
            q->front = q->rear;
        else
            q->front->next = s->next;
        free(s);
        return 1;
    }
}
//main
int main()
{
    int i;
    linkqueue * l;
    l = (linkqueue *)malloc(sizeof(linkqueue));
    initqueue(l);
    for(i = 0; i < 10; i++)
        inqueue(l,i);
    for(i = 0; i < 10; i++)
        outqueue(l);
    
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值