数据结构学习之队列

1. 队列简介

1.1 队列的特点

队列(Queue)与栈一样,是一种线性存储结构,它具有如下特点:
1.队列中的数据元素遵循“先进先出”(First In First Out)的原则,简称FIFO结构。
2.在队尾添加元素,在队头删除元素。

1.2 队列的相关概念

队列的相关概念:
队头与队尾: 允许元素插入的一端称为队尾,允许元素删除的一端称为队头。
入队:队列的插入操作。
出队:队列的删除操作。
例如我们有一个存储整型元素的队列,我们依次入队:{1,2,3}

在这里插入图片描述
添加元素时,元素只能从队尾一端进入队列,也即是2只能跟在1后面,3只能跟在2后面。
如果队列中的元素要出队:
在这里插入图片描述

元素只能从队首出队列,出队列的顺序为:1、2、3,与入队时的顺序一致,这就是所谓的“先进先出”。

1.3 队列的操作

队列通常提供的操作:

  1. 入队: 通常命名为push()
  2. 出队: 通常命名为pop()
  3. 求队列中元素个数size
  4. 判断队列是否为空isEmpty
  5. 获取队首元素front
  6. 返回队尾元素back

1.4 队列的存储结构

队列与栈一样是一种线性结构,因此以常见的线性表如数组、链表作为底层的数据结构。
本文中,我们以数组、链表为底层数据结构构建队列。

2.队列实现

2.1 STL队列queue

2.1.1STL之queue常用操作

  1. 将元素添加到队列尾部push、emplace
  2. 删除队头元素pop
  3. 返回队列的对头元素,但不删除该元素front
  4. 返回队列的队尾元素,但不删除该元素back
  5. 返回队列中元素的个数size
  6. 交换两个队列的元素,只是交换底层数据结构swap

2.1.2 STLqueue操作实例

int STLQueueFunc() {
	queue<int> stlQ;
	stlQ.push(1);
	stlQ.push(2);
	stlQ.push(3);
	//输出队列长度
	cout << "front:" << stlQ.front() << endl;
	cout << "back:" << stlQ.back() << endl;
	stlQ.emplace(4);
	cout << "Size:" << stlQ.size() << endl;
	while (!stlQ.empty())
	{
		cout << stlQ.front() << endl;
		stlQ.pop();
	}
	return 0;
}

2.2基于数组实现循环队列

以数组作为底层数据结构时,一般讲队列实现为循环队列。这是因为队列在顺序存储上的不足:每次从数组头部删除元素(出队)后,需要将头部以后的所有元素往前移动一个位置,这是一个时间复杂度为O(n)的操作:

在这里插入图片描述
可能有人说,把队首标志往后移动不就不用移动元素了吗?的确,但那样会造成数组空间的“流失”。
我们希望队列的插入与删除操作都是O(1)的时间复杂度,同时不会造成数组空间的浪费,我们应该使用循环队列。
所谓的循环队列,可以把数组看出一个首尾相连的圆环,删除元素时将队首标志往后移动,添加元素时若数组尾部已经没有空间,则考虑数组头部的空间是否空闲,如果是,则在数组头部进行插入。
在这里插入图片描述

那么我们如何判断队列是空队列还是已满呢?

  1. 栈空: 队首标志=队尾标志时,表示栈空,即红绿两个标志在图中重叠时为栈空。
  2. 栈满 : 队尾+1 = 队首时,表示栈空。图三最下面的队列即为一个满队列。尽管还有一个空位,我们不存储元素。

2.2.1 循环队列的抽象数据类型

template <typename T>
class LoopQueue
{
public:
    LoopQueue(int c = 10);
    ~LoopQueue();
public:
    bool isEmpty();        //队列的判空
    int size();            //队列的大小
    bool push(T t);        //入队列
    bool pop();            //出队列
    T front();            //队首元素
 
private:
    int capacity;
    int begin;
    int end;
    T*  queue;
};

2.2.2 队列的具体实现

template<typename T>
LoopQueue<T>::LoopQueue(int c = 10)
: capacity(c), begin(0), end(0), queue(nullptr)
{
    queue = new T[capacity];
};
 
template<typename T>
LoopQueue<T>::~LoopQueue()
{
    delete[]queue;
}
 
template <typename T>
bool LoopQueue<T>::isEmpty()
{
    if (begin == end)
        return true;
    return false;
};
 
template<typename T>
int LoopQueue<T>::size()
{
    return (end-begin+capacity)%capacity; //计算队列长度
};
 
template<typename T>
bool LoopQueue<T>::push(T t)
{
    if (end + 1 % capacity == begin) //判断队列是否已满
    {
        return false;
    }
    queue[end] = t;
    end = (end + 1) % capacity;
    return true;
};
 
template <typename T>
bool LoopQueue<T>::pop()
{
    if (end == begin) //判断队列是否为空
    {
        return false;
    }
    begin = (begin + 1) % capacity;
    return true;
};
 
template <typename T>
T LoopQueue<T>::front()
{
    if (end == begin)
    {
        return false;
    }
    return queue[begin];
};

2.2.3 队列测试代码

int main()
{
    LoopQueue<string> queue(6);
    queue.push("one");
    queue.push("two");
    queue.push("three");
    queue.push("four");
    queue.push("five");
    cout << "队列长度" << queue.size() << endl;
    while (!queue.isEmpty())
    {
        cout << queue.front() << endl;
        queue.pop();
    }
    getchar();
    return 0;
 
}

2.3 链队列

链队列是基于链表实现的队列,它不存在数组的O(n)的元素移动问题或空间浪费问题。我们所要确定的就是链表哪头做队首,哪头做队尾。
显然我们应该以链表头部为队首,链表尾部为队尾。存储一个指向队尾的指针,方便从链表尾插入元素;使用带头节点的链表,方便从链表头删除元素。
在这里插入图片描述

2.3.1 链表节点

template<typename T>
struct Node
{
    Node(T t) :value(t), next(nullptr){}
    Node() = default;
 
    T value;
    Node<T> * next;
};
  1. vaule : 链表节点的值
  2. next : 指针,指向下一个节点

2.3.2 队列的抽象数据类型

链队列提供的接口与循环队列一致

template<typename T>
class LinkQueue
{
public:
    LinkQueue();
    ~LinkQueue();
 
    bool isEmpty();
    int size();
    bool pop();
    void push(T t);
    T front();
 
private:
    Node<T>* phead;
    Node<T>* pend;
    int count;
};

2.3.3 队列的具体实现

template<typename T>
LinkQueue<T>::LinkQueue()
    :phead(nullptr),pend(nullptr),count(0)
{
    phead = new Node<T>();
    pend = phead;
    count = 0;
};
 
template <typename T>
LinkQueue<T>::~LinkQueue()
{
    while (phead->next != nullptr)
    {
        Node<T> * pnode = phead;
        phead = phead->next;
    }
};
 
template <typename T>
bool LinkQueue<T>:: isEmpty()
{
    return count==0;
};
 
template <typename T>
int LinkQueue<T>::size()
{
    return count;
};
 
//在队尾插入
template <typename T>
void LinkQueue<T>::push(T t)
{
    Node<T>* pnode = new Node<T>(t);
    pend->next = pnode;
    pend = pnode;
    count++;
};
 
//在队首弹出
template <typename T>
bool LinkQueue<T>::pop()
{
    if (count == 0)
        return false;
    Node<T>* pnode = phead->next;
    phead->next = phead->next->next;
    delete pnode;
    count--;
    return true;
};
 
//获取队首元素
template<typename T>
T LinkQueue<T>::front()
{
    return phead->next->value;
};

2.3.4 队列的代码测试

int _tmain(int argc, _TCHAR* argv[])
{
    LinkQueue<string> lqueue;
    lqueue.push("one");
    lqueue.push("two");
    lqueue.push("three");
    lqueue.push("four");
    lqueue.push("five");
    cout << "队列的大小" << lqueue.size() << endl;
    while (!lqueue.isEmpty())
    {
        cout << lqueue.front() << endl;
        lqueue.pop();
    }
    getchar();
    return 0;
}

循环队列:https://github.com/huanzheWu/Data-Structure/blob/master/LoopQueue/LoopQueue/LoopQueue.h
链队列:https://github.com/huanzheWu/Data-Structure/blob/master/LinkQueue/LinkQueue/LinkQueue.h
转载:http://www.cnblogs.com/QG-whz/p/5171123.html#_label3_0

1.算法是程序的灵魂,优秀的程序在对海量数据处理时,依然保持高速计算,就需要高效的数据结构和算法支撑。2.网上数据结构和算法的课程不少,但存在两个问题:1)授课方式单一,大多是照着代码念一遍,数据结构和算法本身就比较难理解,对基础好的学员来说,还好一点,对基础不好的学生来说,基本上就是听天书了2)说是讲数据结构和算法,但大多是挂羊头卖狗肉,算法讲的很少。 本课程针对上述问题,有针对性的进行了升级 3)授课方式采用图解+算法游戏的方式,让课程生动有趣好理解 4)系统全面的讲解了数据结构和算法, 除常用数据结构和算法外,还包括程序员常用10大算法:二分查找算法(非递归)、分治算法、动态规划算法、KMP算法、贪心算法、普里姆算法、克鲁斯卡尔算法、迪杰斯特拉算法、弗洛伊德算法、马踏棋盘算法。可以解决面试遇到的最短路径、最小生成树、最小连通图、动态规划等问题及衍生出的面试题,让你秒杀其他面试小伙伴3.如果你不想永远都是代码工人,就需要花时间来研究下数据结构和算法。教程内容:本教程是使用Java来讲解数据结构和算法,考虑到数据结构和算法较难,授课采用图解加算法游戏的方式。内容包括: 稀疏数组、单向队列、环形队列、单向链表、双向链表、环形链表、约瑟夫问题、栈、前缀、中缀、后缀表达式、中缀表达式转换为后缀表达式、递归与回溯、迷宫问题、八皇后问题、算法的时间复杂度、冒泡排序、选择排序、插入排序、快速排序、归并排序、希尔排序、基数排序(桶排序)、堆排序、排序速度分析、二分查找、插值查找、斐波那契查找、散列、哈希表、二叉树、二叉树与数组转换、二叉排序树(BST)、AVL树、线索二叉树、赫夫曼树、赫夫曼编码、多路查找树(B树B+树和B*树)、图、图的DFS算法和BFS、程序员常用10大算法、二分查找算法(非递归)、分治算法、动态规划算法、KMP算法、贪心算法、普里姆算法、克鲁斯卡尔算法、迪杰斯特拉算法、弗洛伊德算法马踏棋盘算法。学习目标:通过学习,学员能掌握主流数据结构和算法的实现机制,开阔编程思路,提高优化程序的能力。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页