摘要

  本章介绍了几种基本的数据结构,包括栈、队列、链表以及有根树,讨论了使用指针的简单数据结构来表示动态集合。本章的内容对于学过数据结构的人来说,没有什么难处,简单的总结一下。

1、栈和队列

  栈和队列都是动态集合,元素的出入是规定好的。栈规定元素是先进后出(FILO),队列规定元素是先进先出(FIFO)。栈和队列的实现可以采用数组和链表进行实现。在标准模块库STL中有具体的应用,可以参考http://www.cplusplus.com/reference/。

  栈的基本操作包括入栈push和出栈pop,栈有一个栈顶指针top,指向最新如栈的元素,入栈和出栈操作操作都是从栈顶端进行的。

  队列的基本操作包括入队enqueue和出队dequeue,队列有队头head和队尾tail指针。元素总是从队头出,从队尾入。采用数组实现队列时候,为了合理利用空间,可以采用循环实现队列空间的有效利用。

  关于栈和队列的基本操作如下图所示:

采用数组简单实现一下栈和队列,实现队列时候,长度为n的数组最多可以含有n-1个元素,循环利用,这样方便判断队列是空还是满。

栈的C++程序如下所示:

#include<iostream>
#include<cstdlib>
using namespace std;typedef struct stack
{int *s;int stacksize;int top;
}stack;void init_stack(stack *s,int n)
{s->stacksize=n;s->s=(int*)malloc(sizeof(int)*s->stacksize);s->top=0;
}bool stack_empty(stack *s)
{if(s->top==0)return true;elsereturn false;
}bool stack_full(stack *s)
{if(s->top==s->stacksize)return true;elsereturn false;
}void push(stack *s,int x)
{if(stack_full(s)){cout<<"overflow"<<endl;exit(1);}s->top=s->top+1;s->s[s->top]=x;
}int pop(stack *s)
{int x;if(stack_empty(s)){cout<<"underflow"<<endl;exit(1);}x=s->s[s->top];s->top--;return x;
}
int top(stack *s)
{return s->s[s->top];
}
int main()
{stack s;init_stack(&s,100);push(&s,19);push(&s,23);push(&s,34);push(&s,76);push(&s,65);cout<<"top is "<<top(&s)<<endl;pop(&s);cout<<"top is "<<top(&s)<<endl;
}

队列的C++代码实现:

#include<iostream>
#include<cstdlib>
using namespace std;typedef struct queue
{int *q;int head,tail;int queuesize;
}queue;void init_queue(queue *q,int n)
{q->queuesize=n;q->q=(int*)malloc(sizeof(int)*q->queuesize);q->tail=q->head=0;
}bool queue_empty(queue *q)
{if(q->head==q->tail)return true;elsereturn false;
}bool queue_full(queue *q)
{if(q->tail+1==q->head)return true;elsereturn false;
}int queue_length(queue *q)
{return (q->tail-q->head+q->queuesize)%q->queuesize;
}void enqueue(queue *q,int x)
{if(queue_full(q)){cout<<"queue overflow"<<endl;exit(1);}q->q[q->tail]=x;q->tail=(q->tail+1)%q->queuesize;
}int dequeue(queue *q)
{int x;if(queue_empty(q)){cout<<"queue underflow"<<endl;exit(1);}x=q->q[q->head];q->head=(q->head+1)%q->queuesize;return x;
}int main()
{queue q;init_queue(&q,100);enqueue(&q,10);enqueue(&q,30);cout<<"head: "<<q.head<<" tail: "<<q.tail<<endl;cout<<"value="<<dequeue(&q)<<endl;cout<<"value="<<dequeue(&q)<<endl;cout<<"head: "<<q.head<<" tail: "<<q.tail<<endl;enqueue(&q,10);exit(0);
}

问题:

(1)说明如何用两个栈实现一个队列,并分析有关队列操作的运行时间。(始终用一个栈做为出,一个栈作为入队)

解答:栈中的元素是先进后出,而队列中的元素是先进先出。现有栈s1和s2,s1中存放队列中的结果,s2辅助转换s1为队列。

入队时,将元素压入s1。

出队时,判断s2是否为空,如不为空,则直接弹出顶元素;如为空,则将s1的元素逐个“倒入”s2,把最后一个元素弹出并出队。

(如果s1满了,s2既没有装满也不是非空,此时就不能继续入队了;如果s1满了,但s2是空的,则可以先将s1中的元素压人s2中,然后再进队。)

#include<iostream>
#include<stack>
#include<cstdlib>
using namespace std;template <typename T>
class StackToQueue
{
public:T dequeue();void enqueue(const T &node);StackToQueue(){}~StackToQueue(){}
private:stack<T> stack1;stack<T> stack2;
};template <typename T>
void StackToQueue<T>::enqueue(const T &node)
{stack1.push(node);
}template <typename T>
T StackToQueue<T>::dequeue()
{if(stack2.empty()&&stack1.empty()){cout<<"underflow"<<endl;exit(1);}if(stack2.empty()&&!stack1.empty()){while(!stack1.empty()){T temp=stack1.top();stack1.pop();stack2.push(temp);}}T data=stack2.top();stack2.pop();return data;
}int main()
{StackToQueue<int> sq;sq.enqueue(1);sq.enqueue(2);sq.enqueue(3);cout<<sq.dequeue()<<endl;cout<<sq.dequeue()<<endl;cout<<sq.dequeue()<<endl;cout<<sq.dequeue()<<endl;
}

(2)说明如何用两个队列实现一个栈,并分析有关栈操作的运行时间。(始终保证有一个队列是空的)

需要注意的一点是,如果每次入栈都选则将元素插入到第一个队列中,出队时先将前n-1个元素移交到第二个队列中,然后返回队列一中剩余的唯一一个元素,再将队列二中的元素又依次移交回队列一中,这样做未免效率过于低下。

事实上这样的思路我们可以看作是一直选用队列一作为栈元素的存储容器,而使用队列二作为一个出队时的辅助工具,这样每次出栈时来回复制元素容器元素的操作,效率确实低下。因为两个队列完全一样的,所以我们完全有理由让两个队列轮流作为栈元素的存储容器,这样每次出栈时,只需将所有前n-1个元素从一个队列移交到另一个队列中,然后返回最后一个元素作为出栈结果,这样始终至少有一个队列是空的,而每次进栈时,只需将进占元素放在那个非空队列的末尾(如果两个队列均为空,则随便放在那个里面都行)。这样减少了一半的复制操作。

#include<iostream>
#include<queue>
#include<cstdlib>
using namespace std;template <typename T>
class QueueToStack
{
public:QueueToStack(){}~QueueToStack(){}T pop();void push(const T &node);
private:queue<T> queue1;queue<T> queue2;
};template <typename T>
T QueueToStack<T>::pop()
{T data;if(queue1.empty()&&queue2.empty()){cout<<"underflow"<<endl;exit(1);}if(!queue1.empty())//对工作的队列进行操作
    {     //出队到队列中只剩下一个元素,就可以出栈了while(queue1.size()>1){T temp=queue1.front();queue1.pop();queue2.push(temp);}data=queue1.front();queue1.pop();}else if(!queue2.empty()){while(queue2.size()>1){T temp=queue2.front();queue2.pop();queue1.push(temp);}data=queue2.front();queue2.pop();}return data;
}template <typename T>
void QueueToStack<T>::push(const T &node)
{if(!queue1.empty())//每次都压入到工作的队列中
        queue1.push(node);elsequeue2.push(node);
}int main()
{QueueToStack<int> queue;queue.push(1);queue.push(2);queue.push(3);cout<<queue.pop()<<endl;cout<<queue.pop()<<endl;cout<<queue.pop()<<endl;
}

上面的top没有写

#include <cstdlib>
#include <iostream>
#include <assert.h>
#include <deque>
using namespace std;
/*两个队列模拟一个堆栈*/
/*队列A、B
入栈:将元素依次压入到非空的队列,第一个元素压倒对列A
出栈:把队列A的前n-1个元素倒到队列B,把第n个元素去掉。此时数据在B中,下次操作,则对B操作。
栈顶:把队列A的前n-1个元素倒到队列B,把第n个元素作为栈顶*/
template <typename T>
class MyStack
{
public://入栈,第一个元素进到队列deque1,以后每个元素进到非空的队列void  push(T element){if (deque1.empty() && deque2.empty()){deque1.push_back(element);}else if (!deque1.empty() && deque2.empty()){deque1.push_back(element);}else if (deque1.empty() && !deque2.empty()){deque2.push_back(element);}}//出栈,将非空队列的前n-1个元素转移到另一个空的队列,删除非空队列的第n个元素void pop(){if (!deque1.empty()){int size = deque1.size();for (int i=0; i<size-1; i++){deque2.push_back(deque1.front());deque1.pop_front();}deque1.pop_front();}else{int size = deque2.size();for (int i=0; i<size-1; i++){deque1.push_back(deque2.front());deque2.pop_front();}deque2.pop_front();}}//栈顶元素,将非空队列的前n-1个元素转移到另一个空的队列,将非空队列的第n个元素返回
    T top(){if (!deque1.empty()){int size = deque1.size();for (int i=0; i<size-1; i++){deque2.push_back(deque1.front());deque1.pop_front();}T temp = deque1.front();deque1.pop_front();deque2.push_back(temp);return temp;}else{int size = deque2.size();for (int i=0; i<size-1; i++){deque1.push_back(deque2.front());deque2.pop_front();}T temp = deque2.front();deque2.pop_front();deque1.push_back(temp);return temp;}}//栈是否为空bool empty(){return (deque1.empty()&&deque2.empty());}
private:deque<T> deque1;deque<T> deque2;
};
int main(int argc, char *argv[])
{MyStack<int> my;for (int i=0; i<10; i++){my.push(i);}while (!my.empty()){cout<<my.top()<<" ";my.pop();}cout<<endl;
}

第十章 基本数据结构——栈和队列相关推荐

  1. 数据结构栈和队列_使您的列表更上一层楼:链接列表和队列数据结构

    数据结构栈和队列 When you want to store several elements somewhere in a program, the go-to data type is an a ...

  2. 数据结构栈与队列的应用之汽车轮渡问题——自己的一些理解

    本题摘自王道数据结构栈与队列的应用的课后题,题目如下: 某汽车轮渡口,过江渡船每次能载10辆汽车过江.过江车辆分为客车类和货车类,上渡船有如下规定:同类车先到先上船,客车先于货车上船,且每上4辆客车, ...

  3. 数据结构——栈与队列相关题目

    数据结构--栈与队列相关题目 232. 用栈实现队列 思路 225. 用队列实现栈 1.两个队列实现栈 2.一个队列实现栈 20. 有效的括号 思路 1047. 删除字符串中的所有相邻重复项 思路 1 ...

  4. 大话数据结构-栈与队列

    文章知识点来至于大话数据结构里边章节知识, 这篇主要介绍栈与队列在计算机中存储形式, 以及在某些算法领域中对栈和队列的相关应用.章节最后介绍了著名的逆波兰表达式, 以及通过算法来实现该表达式的运算过程 ...

  5. 数据结构——栈与队列操作(用栈模拟队列)

    [栈与队列操作] 问题描述:假设有两个长度相同的栈 S1,S2,已知以下入栈.出栈.判栈满和判栈空操作: void Push(S,x); Elemtype Pop(S); bool StackFull ...

  6. 【数据结构-栈和队列】详解栈和队列(代码+STL+原理)

    一.栈的应用 栈是一种先进后出(FILO)的数据结构 1.1 栈的操作实现 清空(clear): // 栈的清空操作就是把栈顶top置为-1 void clear(){top=-1; } // 清空栈 ...

  7. 算法与数据结构 -- 栈与队列(四)

    栈与队列定义了数据的操作 一.栈 栈是一种先入先出的数据结构.可以用顺序表实现,也可以用链表实现 栈操作 判断是否为空 压栈.入栈push 出栈 pop 返回栈顶元素 peek 栈的元素个数 # co ...

  8. 六十二、数据结构栈和队列的相互实现

    @Author:Runsen 编程的本质来源于算法,而算法的本质来源于数学,编程只不过将数学题进行代码化. ---- Runsen 算法,一门既不容易入门,也不容易精通的学问. 栈和队列都是用来保存数 ...

  9. 数据结构栈和队列以及常见算法题

    栈 概念:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作.进行数据插入和删除操作的一端称为栈顶,另一端称为栈底.栈中的数据元素遵守后进先出LIFO(Last In First Out)的 ...

最新文章

  1. 在Dos下运行exe程序的时候出现找不到Cygwin1.dll文件的情况总结
  2. hdu-----(4514)湫湫系列故事——设计风景线(树形DP+并查集)
  3. java 企业门户网站 源码 自适应响应式 freemarker 静态引擎 html5 SSM
  4. pythonunicode转为字符串_python中将 \\uxxxx转换为 Unicode字符串
  5. UITableView移除某一行cell的分割线
  6. usb serial port 驱动_tty初探 — uart驱动框架分析
  7. golang刷Leetcode系列 --- 实现strStr()
  8. linux可上网limbo镜像,limbo模拟器win10镜像
  9. 【python】教你使用seLeniun爬取淘宝商品数据(内含完整源码)
  10. a/an,the,said的用法
  11. C++调用webservice服务生成客户端代码-gsoap
  12. 数据库初级入门sqlite3版本
  13. 什么样的耳机戴着舒服些、最好用的的几款骨传导蓝牙耳机推荐
  14. 手机通讯录、联系人的备份、恢复经验
  15. 井字棋游戏案例C++语言
  16. 微电子跨专业考计算机,2018考研:盲目跨专业可能遇到的四个问题
  17. 如何禁用Windows更新
  18. 【科普】显示器连接线有哪几种都长什么样子
  19. Gradle 下载依赖失败解决方法
  20. Linux内核的构成,Linux内核学习路线知识点总结以及视频

热门文章

  1. php获取svn文件,然后ftp上传服务器代码
  2. PHP简单实现一言 / 随机一句功能
  3. datatables如何把列设置成hidden隐藏域?
  4. [Contest20171109]函数(lipshitz)
  5. Hive之 Hql语法解析
  6. IntelliJ IDEA添加过滤文件或目录
  7. 【Codevs1346】HelloWorld编译器
  8. C++中string查找和取子串和整形转化
  9. golang rpc的两种调用方法
  10. [Spring入门学习笔记][静态资源]