基于链式存储的队列

来源:互联网 发布:linux usb驱动开发 编辑:程序博客网 时间:2024/06/03 13:52

日常生活中我们吃饭,买票等都是要排队的,这里的排队其实就是对应着数据结构中的队列了。其中排队过程中不允许插队也是一个能反应队列结构性质的表现吧。队列和栈一样,是一个被限制存取的线性结构。普通队列规定只能在队头出,只能在队尾进,这也是为什么不允许插队的原因了。当然这里讨论的是最简单的最普通的队列了,当然还是有一些特殊的队列的,比如双端队列,优先级队列等,后续细说。

基于链式存储的队列结构中,结点类型和之前的单链表是类似的,简直是一样的。

#pragma once#include<iostream>using namespace std;template<class T>class LinkNode{public:T data;LinkNode<T> *next;//指针域public:LinkNode();LinkNode(T &da);~LinkNode();};template<class T>LinkNode<T>::LinkNode()//初始化 用于构建一个头结点时使用{next = NULL;//指针域默认为NULL}template<class T>LinkNode<T>::LinkNode(T &da){data = da;//初始化 用于根据元素值new出新的结点next = NULL;}template<class T>LinkNode<T>::~LinkNode(){//可以为空}

链式队列和单链表比起来是多了一个队尾指针,用来指向最后一个结点,队头指针仍然指向当前队列的第一个结点。进队列的时候要考虑一个问题,那就是这个队列是不是为空的。如果是空队列的话,那需要将队头指针(front)和队尾指针(rear)同时指向新的结点(同时也是第一个结点)。如果队列不为空的话,那就直接将新结点被rear所指即可。所以这里在进队列操作的时候要多一步考虑了。可是我们可以像单链表一样,增加一个头结点,这个头结点什么也不做,只是开辟出来一个结点空间让对头和队尾都指向即可。这时候再进队列的时候就不用考虑队列是否为空了,直接链接在rear的后面OK。

#pragma once#include"LinkNode.h"#include<iostream>using namespace std;template<class T>class Queue{protected:LinkNode<T> *front;//头指针LinkNode<T> *rear;//尾指针public:Queue();Queue(Queue<T> &Q);//队列 深复制~Queue();void ClearQueue();//销毁队列T De_Queue();//出队列,仅仅在头指针改动,(要做一个 当前出队列指针是否为尾指针的判断)返回元素值,也可返回指针,但后者易造成内存泄露void In_Queue(T &elem);//入队列 仅仅在尾指针改动LinkNode<T> * GetHead();//返回队列头指针LinkNode<T> * GetRear();//返回队列尾指针int Length();//返回队列的元素个数void output();//按顺序 一次性输出队列void operator= (Queue<T> &Q);//复制};template<class T>Queue<T>::Queue(){front = new LinkNode<T>;//调用无参 构造函数,data域未知,指针域为NULLrear = front;//初始化 把头指针赋给尾指针,在随后的插入过程中 尾指针后移}template<class T>Queue<T>::Queue(Queue<T> &Q){front = new LinkNode<T>;//先初始化当前队列rear = front;//Q为空的时候 直接退出if(Q.GetHead() == Q.GetRear())//首尾指针相同 即为空队列{cout<<"空队列 无须复制构造"<<endl;exit(1);}//下面执行的都是在Q为非空的情况下LinkNode<T> *current = Q.GetHead() ->next;//从实际上的队列第一位 开始遍历LinkNode<T> *Q_REAR = Q.GetRear();//返回尾指针 作为循环判断的条件LinkNode<T> *newNode;T elem;while(current != Q_REAR)//在当前指针没碰到队尾指针时{elem = current->data;//提取 值域newNode = new LinkNode<T>(elem);//根据元素值 构造一个完全一样的rear->next = newNode;//插入rear = newNode;current = current->next;}//剩下尾指针的没有复制elem = Q_REAR->data;//Q的队尾指针newNode = new LinkNode<T>(elem);rear->next = newNode;rear = newNode;}template<class T>Queue<T>::~Queue(){Queue<T>::ClearQueue();//销毁}template<class T>void Queue<T>::ClearQueue(){if(front == rear){cout<<"空队列,无须销毁"<<endl;//exit(1);}//不为空队列LinkNode<T> *del = front->next;while(del != rear){front->next = del->next;//前移delete del;del = front->next;}//如果不为空但跳过循环则为队列中一个元素delete del;//删除尾指针rear = front;//置为空队列}template<class T>T Queue<T>::De_Queue()//出队列 删除队首结点{T elem;LinkNode<T> *del = front->next;//把头结点的next赋给del 待删除front->next = del->next;//往前移动一位if(rear == del)//判断要删除的指针是否为队尾的元素,如果是删除之后就是空队列rear = front;//空队列 把首指针赋给尾指针elem = del->data;//提取待删除指针的 值域delete del;return elem;}template<class T>void Queue<T>::In_Queue(T &elem)//入队列,后面修改尾指针即可 不需做判断{LinkNode<T> *newNode = new LinkNode<T>(elem);if(newNode == NULL){cout<<"内存分配失败"<<endl;exit(1);}rear->next = newNode;//把新结点 接到尾指针的后面rear = newNode;//再把尾指针后移,两个顺序不能变}template<class T>LinkNode<T> * Queue<T>::GetHead(){return front;//首指针}template<class T>LinkNode<T> * Queue<T>::GetRear(){return rear;//尾指针}template<class T>int Queue<T>::Length(){int count = 0;//局部变量最好初始化 否则在无意中使用时会出错LinkNode<T> *current = front;//把首指针赋给当前指针用于遍历while(current != NULL)//如果为空队列 则不执行循环 直接返回count=0{current =current->next;count++;}return count;}template<class T>void Queue<T>::output(){int count = 0;LinkNode<T> *current = front->next;while(current != rear)//没碰到尾指针{cout<<"#"<<count+1<<":"<<current->data<<endl;current = current->next;count++;}//输出队尾cout<<"#"<<count+1<<":"<<rear->data<<endl;}template<class T>void Queue<T>::operator= (Queue<T> &Q){front = new LinkNode<T>;//先初始化当前队列rear = front;////Q为空的时候 直接退出//if(Q.GetHead() == Q.GetRear())//首尾指针相同 即为空队列//{//cout<<"空队列 无须复制构造"<<endl;////exit(1);//}//Queue<T>::ClearQueue();//在被复制之前 先销毁队列//下面执行的都是在Q为非空的情况下LinkNode<T> *current = Q.GetHead() ->next;//从实际上的队列第一位 开始遍历LinkNode<T> *Q_REAR = Q.GetRear();//返回尾指针 作为循环判断的条件LinkNode<T> *newNode;T elem;while(current != Q_REAR)//在当前指针没碰到队尾指针时{elem = current->data;//提取 值域newNode = new LinkNode<T>(elem);//根据元素值 构造一个完全一样的rear->next = newNode;//插入rear = newNode;current = current->next;}//剩下尾指针的没有复制elem = Q_REAR->data;//Q的队尾指针newNode = new LinkNode<T>(elem);rear->next = newNode;rear = newNode;}
下面是主函数的测试:

#include"queue.h"#include<iostream>using namespace std;void main(){Queue<int> qu;for(int i=0;i<5;i++)qu.In_Queue(i);qu.output();cout<<endl;Queue<int> qu1;for(int i=0;i<3;i++)qu1.In_Queue(i);qu1.output();cout<<endl;qu1 = qu;qu1.output();}

原创粉丝点击