基于链式存储的队列
2013-01-22 18:34
295 查看
日常生活中我们吃饭,买票等都是要排队的,这里的排队其实就是对应着数据结构中的队列了。其中排队过程中不允许插队也是一个能反应队列结构性质的表现吧。队列和栈一样,是一个被限制存取的线性结构。普通队列规定只能在队头出,只能在队尾进,这也是为什么不允许插队的原因了。当然这里讨论的是最简单的最普通的队列了,当然还是有一些特殊的队列的,比如双端队列,优先级队列等,后续细说。
基于链式存储的队列结构中,结点类型和之前的单链表是类似的,简直是一样的。
链式队列和单链表比起来是多了一个队尾指针,用来指向最后一个结点,队头指针仍然指向当前队列的第一个结点。进队列的时候要考虑一个问题,那就是这个队列是不是为空的。如果是空队列的话,那需要将队头指针(front)和队尾指针(rear)同时指向新的结点(同时也是第一个结点)。如果队列不为空的话,那就直接将新结点被rear所指即可。所以这里在进队列操作的时候要多一步考虑了。可是我们可以像单链表一样,增加一个头结点,这个头结点什么也不做,只是开辟出来一个结点空间让对头和队尾都指向即可。这时候再进队列的时候就不用考虑队列是否为空了,直接链接在rear的后面OK。
基于链式存储的队列结构中,结点类型和之前的单链表是类似的,简直是一样的。
#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域未知,指针域为NULL rear = 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(); }
相关文章推荐
- 队列的顺序存储实现和链式存储实现
- 队列的链式存储方式的实现(Java语言描述)
- 队列(C语言实现,基于链式结构)
- 队列的链式存储结构与操作
- 队列链式存储
- 队列的链式存储及实现
- 队列的链式存储---链表实现(有头结点)
- 队列的链式存储方式的实现(Java语言描述)
- 基于TableStore(表格存储)构建简易海量Topic消息队列
- 队列的顺序存储和链式存储实现
- 队列操作的实现-链式存储
- 数据结构--队列--链式存储
- 队列链式存储实现
- [数据结构]程杰队列的链式存储结构及实现代码
- C++中实现队列类链式存储与栈类链式存储的代码示例
- 数据结构-队列的链式存储实现操作
- 队列的链式存储结构及实现
- 队列的链式存储
- 数据结构学习之队列(链式存储)
- 队列的顺序存储与链式存储