目录
- 数据结构:
- 逻辑结构:数组,栈,队列,字符串,树,图
- 存储结构:顺序存储,链式存储
- C++常用的数据结构有:string , stack , queue , deque , vector , list , map , iterators.
一.栈
栈可以看成一种特殊的线性表,特殊之处在于只能在表头或者表尾进行删除和插入操作。
1.栈的基本操作
push(): 向栈内压入一个成员;
pop(): 从栈顶弹出一个成员;
empty(): 如果栈为空返回true,否则返回false;
top(): 返回栈顶,但不删除成员;
size(): 返回栈内元素的大小
例子:
#include <iostream>
#include <stack>
using namespace std;
int main(){
//定义一个整形的栈
stack <int> mStack;
cout<<"the size of mStack is:"<<mStack.size()<<endl;
//向栈中加入元素
mStack.push(1);
mStack.push(2);
mStack.push(3);
mStack.push(4);
cout<<"after push , the size of mStack is:"<<mStack.size()<<endl;
//弹出栈中的内容
while(!mStack.empty()){ //栈的遍历
cout<<"the data will be pop is:"<<mStack.top()<<endl;
mStack.pop();
cout<<"after pop ,the len of stack is:"<<mStack.size()<<endl;
}
// for(int i =0 ; i < 4;i++){
// mStack.pop(); //出栈
// cout<<"the "<<i<<" pop is:"<<mStack.top()<<endl;
// cout<<"the len "<<i<<" pop is:"<<mStack.size()<<endl;
// }
return 0;
}
the size of mStack is:0
after push , the size of mStack is:4
the data will be pop is:4
after pop ,the len of stack is:3
the data will be pop is:3
after pop ,the len of stack is:2
the data will be pop is:2
after pop ,the len of stack is:1
the data will be pop is:1
after pop ,the len of stack is:0
2.使用C++模板类实现栈
虽然C++自带了stack的模板类,也实现了大部分的栈的操作,但是我们还是需要自己实现栈这种逻辑结构。
#include <iostream>
#include <stack>
using namespace std;
#define MAXSIZE 0XFFFF
template<class T>
class myStack{
private:
int top; //栈顶指针,顺序存储中位数组的下标,所以必须为整形
T* my_s; //栈的存储空间指针
int maxSize; //栈最大的存储空间
public:
//默认的构造函数
myStack():top(-1),maxSize(MAXSIZE){
my_s = new T[maxSize]; //为栈申请存储
if(my_s == NULL){
cerr<<"内存分配失败!"<<endl;
exit(1);
}
}
//带参数的构造函数
myStack(int size):top(-1),maxSize(size){
my_s = new T[maxSize]; //为栈申请存储
if(my_s == NULL){
cerr<<"内存分配失败!"<<endl;
exit(1);
}
}
~myStack(){
cout<<"delete the stack!"<<endl;
delete [] my_s; //删除整个栈
}
bool isEmpty();//判空函数
void push(T data); //压栈函数
void pop(); //出栈函数
T getTopValue(); //取出栈顶元素
int size(); //判断栈的大小
};
//函数定义
template<class T>
bool myStack<T>::isEmpty(){
if(top==-1){ //栈顶指针为-1表示栈空
return true;
}
else{
return false;
}
}
template<class T>
void myStack<T>::push(T data){
if((top+1) < maxSize){
my_s[++top] = data; //先将栈顶指针加一,然后在给栈顶赋值
}
else{
cout<<"栈满!"<<endl;
}
}
template<class T>
void myStack<T>::pop(){
if(top == -1){
cout<<"栈空!!"<<endl;
}else{
top--; //栈顶指针减一
}
}
template<class T>
T myStack<T>::getTopValue(){
if(top == -1){
cout<<"栈空!!"<<endl;
}else{
return my_s[top];
}
}
template<class T>
int myStack<T>::size(){
return top+1;
}
int main(){
// myStack<int> mStack; //创建一个栈
// cout<<"The size of mStack is "<<mStack.size()<<endl;
// //压栈
// mStack.push(1);
// mStack.push(2);
// mStack.push(3);
// mStack.push(4);
// cout<<"After push , the size of mStack is "<<mStack.size()<<endl;
// while(!mStack.isEmpty()){
// cout<<"the top value of mStack is : "<<mStack.getTopValue()<<endl;
// mStack.pop();
// cout<<"After pop , the size of mStack is "<<mStack.size()<<endl;
// }
myStack<double> mStack; //创建一个栈
cout<<"The size of mStack is "<<mStack.size()<<endl;
//压栈
mStack.push(1.1);
mStack.push(2.4);
mStack.push(3.5);
mStack.push(4.8);
cout<<"After push , the size of mStack is "<<mStack.size()<<endl;
//出栈
while(!mStack.isEmpty()){
cout<<"the top value of mStack is : "<<mStack.getTopValue()<<endl;
mStack.pop();
cout<<"After pop , the size of mStack is "<<mStack.size()<<endl;
}
return 0;
}
The size of mStack is 0
After push , the size of mStack is 4
the top value of mStack is : 4.8
After pop , the size of mStack is 3
the top value of mStack is : 3.5
After pop , the size of mStack is 2
the top value of mStack is : 2.4
After pop , the size of mStack is 1
the top value of mStack is : 1.1
After pop , the size of mStack is 0
delete the stack!
二.队列
队列也是一种特殊的线性表,它只允许在表的一头插入元素(队尾),表的另一头删除元素(队头)。
1.队列的基本操作
q.empty() 如果队列为空返回true,否则返回false
q.size() 返回队列中元素的个数
q.pop() 删除队列首元素但不返回其值
q.push() 在队尾压入新元素
q.front() 返回队首元素的值,但不删除该元素
q.back() 返回队列尾元素的值,但不删除该元素
例子(使用c++自带的库实现的)
#include <iostream>
#include <queue>
using namespace std;
int main(){
queue<int> mQueue; //创建一个新的队列
cout<<"the size of mQueue is: "<<mQueue.size()<<endl;
cout<<"mQueue is empty?: "<<mQueue.empty()<<endl;
//入队
mQueue.push(1);
mQueue.push(2);
mQueue.push(3);
mQueue.push(4);
cout<<"after push , the size of mQueue is: "<<mQueue.size()<<endl;
cout<<"the front data of mQueue is: "<<mQueue.front()<<endl;
cout<<"the back data of mQueue is: "<<mQueue.back()<<endl;
while(!mQueue.empty()){
cout<<"the front data of mQueue is: "<<mQueue.front()<<endl;
mQueue.pop();
cout<<"after pop , the size of mQueue is: "<<mQueue.size()<<endl;
}
return 0;
}
the size of mQueue is: 0
mQueue is empty?: 1
after push , the size of mQueue is: 4
the front data of mQueue is: 1
the back data of mQueue is: 4
the front data of mQueue is: 1
after pop , the size of mQueue is: 3
the front data of mQueue is: 2
after pop , the size of mQueue is: 2
the front data of mQueue is: 3
after pop , the size of mQueue is: 1
the front data of mQueue is: 4
after pop , the size of mQueue is: 0
注意
由于单端队列的空间利用率非常低,几乎就是一次性的(只要入队满了,然后全部出队后,便不可再用),所以此处就不讨论自己实现单端队列了。
2.循环队列
循环队列中判断队空的方法是判断front==rear,队满的方法是判断front=(rear+1)%maxSize。
可以解决单端队列中空间一次性消耗的问题
循环队列顺序存储
#include <iostream>
#include <queue>
using namespace std;
#define MAXSIZE 0XFFFF
template<class T>
class myQueue{
private:
int front,rear; //队头和队尾元素
T* my_q; //队列的存储空间
int maxSize; //最大的队列存储空间
public:
//默认构造函数
myQueue():front(-1),rear(-1),maxSize(MAXSIZE){
my_q = new T[maxSize]; //申请内存
if(my_q == NULL){
cerr<<"内存申请失败!!"<<endl;
exit(1);
}
}
//带参数的构造函数
myQueue(int size):front(-1),rear(-1),maxSize(size){
my_q = new T[maxSize]; //申请内存
if(my_q == NULL){
cerr<<"内存申请失败!!"<<endl;
exit(1);
}
}
//析构函数
~myQueue(){
cout<<"delete the queue!!!"<<endl;
delete [] my_q;
}
//操作函数
bool isEmpty(); //判空
void push(T data); //入队操作
void pop(); //出队操作
T getFrontData(); //获取队头元素
T getRearData(); //获取队尾元素
int size(); //获取队列长度
};
template<class T>
bool myQueue<T>::isEmpty(){
if(front == rear){ //判空条件
return true;
}else{
return false;
}
}
template<class T>
void myQueue<T>::push(T data){
if((rear+1)%maxSize == front){ //队列满时候的条件
cout<<"队列满了!!"<<endl;
}else{
my_q[rear] = data; //首先队尾元素赋值
rear = (rear+1) % maxSize;
}
}
template<class T>
void myQueue<T>::pop(){
if(rear == front){
cout<<"队列为空!!"<<endl;
}else{
front = (front+1) % maxSize; //队头指针加一
}
}
template<class T>
T myQueue<T>::getFrontData(){
if(rear == front){
cout<<"队列为空!!"<<endl;
}else{
return my_q[front];
}
}
template<class T>
T myQueue<T>::getRearData(){
if(rear == front){
cout<<"队列为空!!"<<endl;
}else{
return my_q[rear];
}
}
template<class T>
int myQueue<T>::size(){
return (rear-front+maxSize)%maxSize; //队列长度计算
}
//main loop
int main(){
myQueue<int> mQueue;//创建一个新的队列
cout<<"the size of mQueue is: "<<mQueue.size()<<endl;
cout<<"mQueue is empty?: "<<mQueue.isEmpty()<<endl;
//入队
mQueue.push(1);
mQueue.push(2);
mQueue.push(3);
mQueue.push(4);
cout<<"after push , the size of mQueue is: "<<mQueue.size()<<endl;
cout<<"the front data of mQueue is: "<<mQueue.getFrontData()<<endl;
cout<<"the back data of mQueue is: "<<mQueue.getRearData()<<endl;
while(!mQueue.isEmpty()){
cout<<"the front data of mQueue is: "<<mQueue.getFrontData()<<endl;
mQueue.pop();
cout<<"after pop , the size of mQueue is: "<<mQueue.size()<<endl;
}
return 0;
}
the size of mQueue is: 0
mQueue is empty?: 1
after push , the size of mQueue is: 4
the front data of mQueue is: 1
the back data of mQueue is: 0
the front data of mQueue is: 1
after pop , the size of mQueue is: 3
the front data of mQueue is: 2
after pop , the size of mQueue is: 2
the front data of mQueue is: 3
after pop , the size of mQueue is: 1
the front data of mQueue is: 4
after pop , the size of mQueue is: 0
delete the queue!!!
循环队列链式存储
#include <iostream>
using namespace std;
template<class T>
struct LinkNode{
T data;
LinkNode<T> *link;
LinkNode(T& x,LinkNode<T> *l=NULL){
data=x;
link=l;
}
};
template<class T>
class LinkedQueue{
protected:
LinkNode<T> *front,*rear;
public:
LinkedQueue(){
front=rear=NULL;
}
~LinkedQueue(){
makeEmpty();
}
bool enQueue(T& x){
if(front==NULL)
front=rear=new LinkNode<T>(x);
else{
rear=rear->link=new LinkNode<T>(x);
}
return true;
}
bool deQueue(T& x){
if(isEmpty()) return false;
LinkNode<T> *p=front;
x=front->data;
front=front->link;
delete p;
return true;
}
bool getFront(T& x)const{
if(isEmpty()) return false;
x=front->data;
return true;
}
void makeEmpty(){
LinkNode<T> *p;
while(front!=NULL){
p=front;
front=front->link;
delete p;
}
}
bool isEmpty()const{
return (front==NULL)?true:false;
}
int getSize()const{
LinkNode<T> *p;
int count=0;
p=front;
while(p!=NULL){
count++;
p=p->link;
}
return count;
}
};
void menu(){
cout<<"1.入队"<<endl;
cout<<"2.获取队首元素"<<endl;
cout<<"3.出队"<<endl;
cout<<"4.队列置空"<<endl;
cout<<"5.获取队中元素数量"<<endl;
cout<<"6.退出"<<endl;
}
void function(int num,LinkedQueue<int> *lq){
switch(num){
int x;
case 1:
cin>>x;
lq->enQueue(x);
break;
case 2:
lq->getFront(x);
cout<<x<<endl;
break;
case 3:
lq->deQueue(x);
break;
case 4:
lq->makeEmpty();
break;
case 5:
x=lq->getSize();
cout<<x<<endl;
break;
default:
exit(1);
}
}
int main(int argc, char** argv) {
LinkedQueue<int> *lq=new LinkedQueue<int>;
int num;
while(true){
menu();
cin>>num;
function(num,lq);
}
delete lq;
return 0;
}
3.双端队列
可以在两头进行插入和删除操作的队列
deque k; 定义一个deque的变量(定义时已经初始化)
例如: deque k;
k.empty() ------ 查看是否为空范例,是的话返回1,不是返回0
k.clear() ------ 清除队列里的所有数据
k.push_front(i)------ 从已有元素前面增加元素i(队伍大小不预设)
k.push_back(i) ------ 从已有元素后面增加元素i(队伍大小不预设)
k.pop_front() ------ 清除第一个元素
k.pop_back() ------ 清除最后一个元素
k.front() ------ 显示第一个元素
k.back() ------ 显示最后一个元素
k.size() ------ 输出现有元素的个数
例子(使用c++自带的库实现的)
#include <iostream>
#include <deque>
using namespace std;
//main loop
int main(){
deque<int> myDeque;//创建一个双端队列
cout<<"the size of myDeque is: "<<myDeque.size()<<endl;
cout<<"myDeque is empty? : "<<myDeque.empty()<<endl;
//从对头插入元素
myDeque.push_front(1);
myDeque.push_front(2);
myDeque.push_front(4);
myDeque.push_front(3);
//从队尾插入
myDeque.push_back(0);
myDeque.push_back(-1);
myDeque.push_back(-1);
myDeque.push_back(-3);
//从队头出队
deque<int> tempQueue = myDeque;
while(!tempQueue.empty()){
cout<<"the front data of queue is: "<<tempQueue.front()<<endl;
tempQueue.pop_front();
cout<<"the size of myDeque is: "<<tempQueue.size()<<endl;
}
//从队尾出队
deque<int> tempQueue1 = myDeque;
while(!tempQueue1.empty()){
cout<<"the front data of queue is: "<<tempQueue1.back()<<endl;
tempQueue1.pop_back();
cout<<"the size of myDeque is: "<<tempQueue1.size()<<endl;
}
//清空队列
deque<int> tempQueue2 = myDeque;
cout<<"the size of myDeque is: "<<tempQueue2.size()<<endl;
tempQueue2.clear();
cout<<"the size of myDeque1 is: "<<tempQueue2.size()<<endl;
return 0;
}
the size of myDeque is: 0
myDeque is empty? : 1
the front data of queue is: 3
the size of myDeque is: 7
the front data of queue is: 4
the size of myDeque is: 6
the front data of queue is: 2
the size of myDeque is: 5
the front data of queue is: 1
the size of myDeque is: 4
the front data of queue is: 0
the size of myDeque is: 3
the front data of queue is: -1
the size of myDeque is: 2
the front data of queue is: -1
the size of myDeque is: 1
the front data of queue is: -3
the size of myDeque is: 0
the front data of queue is: -3
the size of myDeque is: 7
the front data of queue is: -1
the size of myDeque is: 6
the front data of queue is: -1
the size of myDeque is: 5
the front data of queue is: 0
the size of myDeque is: 4
the front data of queue is: 1
the size of myDeque is: 3
the front data of queue is: 2
the size of myDeque is: 2
the front data of queue is: 4
the size of myDeque is: 1
the front data of queue is: 3
the size of myDeque is: 0
the size of myDeque is: 8
the size of myDeque1 is: 0