数据结构复习——队列
一.基本概念(个人理解)
队列也是一种特殊的线性表,其限定在于只能在表的一端(尾)入队,即加入新元素,而在另一端(首)进行出队,删除操作。与栈相反,队列的特点在于“先进先出”(FIFO)。个人认为队列还是非常形象的,银行,检票口排队,行李放在传送带上接受检查的过程等等,都是队列的具体案例。
二.基本操作
对队列的基本操作有:
1.初始化队列
2.入队操作(将元素从尾部加入队列)
3.出队操作(从头部删除元素)
4.判断是否为空队列
5.清除,销毁操作
6.遍历输出整个队列的内容
三.实现分析(c++,链式)
个人认为队列用链表来实现非常舒服。队列的出队入队是较为频繁的,之前做过很多基于BFS的迷宫题,用stl库的队列时就看得出来。链式队列不用考虑队列的长度限制,添加删除都是动态的,出错的可能性也更小。而且一个单链表就能够实现,只是需要头尾指针,思路也较为清晰。
(一)数据结构设计分析
按惯例,先来节点的定义,与其他链式结构定义没有什么差别
节点用结构体来实现,包含:
存放的数据 T data
下一个节点的地址 *pnext
然后是队列My_Queue的定义,包含:
public:
构造函数
析构函数
初始化队列函数init
入队append
出队out
遍历traversing
清除整个队列
判断是否为空队列
得到队列元素个数的函数
private:
头节点指针
尾节点指针
队列长度
(二)相关定义及声明
节点定义
template<typename T>
class Queue_Node{
public:
T data;
Queue_Node<T> *pnext;
};
队列定义
class My_Queue{
public:
My_Queue();
~My_Queue();
void Init_Queue();
void AppendItem(T inpdata);
T OutItem();
void Traversing();
void Queue_Clear();
bool JudgeEmpty();
int Queue_Size() const{return length;}
private:
Queue_Node<T> *head;
Queue_Node<T> *tail;
int length;
};
(三)函数实现代码
#include<iostream>
#include<string>
using std::string;
template<typename T>
class Queue_Node{
public:
T data;
Queue_Node<T> *pnext;
};
template<typename T>
class My_Queue{
public:
My_Queue();
~My_Queue();
void Init_Queue();
void AppendItem(T inpdata);
T OutItem();
void Traversing();
void Queue_Clear();
bool JudgeEmpty();
int Queue_Size() const{return length;}
private:
Queue_Node<T> *head;
Queue_Node<T> *tail;
int length;
};
template<typename T>
My_Queue<T>::My_Queue()
{
Init_Queue();
}
template<typename T>
My_Queue<T>::~My_Queue()
{
Queue_Clear();
std::cout<<"destruction complete"<<std::endl;
}
template<typename T>
void My_Queue<T>::Init_Queue()
{
head=NULL;
tail=NULL;
length=0;
}
template<typename T>
void My_Queue<T>::AppendItem(T inpdata)
{
Queue_Node<T> *next=new Queue_Node<T>;
next->data=inpdata;
next->pnext=NULL;
if(length==0)
{
head=next;
tail=next;
}
else
{
tail->pnext=next;
tail=tail->pnext;
}
length++;
}
template<typename T>
T My_Queue<T>::OutItem()
{
Queue_Node<T> *next_ptr;
T temp=head->data;
if(head==NULL)
{
std::cout<<"the queue is empty"<<std::endl;
}
else if(head&&head->pnext==NULL)
{
delete head;
length--;
}
else
{
next_ptr=head;
next_ptr=next_ptr->pnext;
delete head;
head=next_ptr;
length--;
}
return temp;
}
template<typename T>
void My_Queue<T>::Traversing()
{
Queue_Node<T> *trav_ptr=head;
std::cout<<"head->";
while(trav_ptr!=NULL)
{
std::cout<<trav_ptr->data<<"|";
trav_ptr=trav_ptr->pnext;
}
std::cout<<"->tail";
std::cout<<"\n";
}
template<typename T>
void My_Queue<T>::Queue_Clear()
{
Queue_Node<T> *next_ptr=head;
while(next_ptr!=NULL)
{
next_ptr=next_ptr->pnext;
delete head;
head=next_ptr;
}
}
template<typename T>
bool My_Queue<T>::JudgeEmpty()
{
if(length>0)return false;
else return true;
}
这回就比较简洁了,边写边优化代码
(四)测试一下
int main()
{
My_Queue<int> q1;
int i=0;
q1.AppendItem(1);
q1.AppendItem(2);
q1.AppendItem(3);
q1.AppendItem(4);
q1.AppendItem(5);
q1.Traversing();
i=q1.OutItem();
i=q1.OutItem();
q1.Traversing();
return 0;
}
结果:
没问题,这回编译终于一遍过了,感觉写代码还是熟能生巧