C++学习笔记(四)——栈,队列与单例模式
本文通过原理解释与代码实现两个方面来解释栈、队列与单例模式。
栈的原理与实现
栈是一种==“先进后出”==的数据结构,示意图如下图(图一):
图一就是一个栈的示意图,该栈的大小为8,现有6个元素。栈顶(_top)元素为5。对栈的操作有:
- 初始化:创建一个空栈
- 压栈:将一个元素放入栈中
- 出栈:将栈顶元素拿出栈
- 判空:判断栈是否为空
- 清空:清空栈的所有元素
- 查看顶元素;
- 查看当前栈的长度;
- 判满:判断栈是否满
代码实现有两种方式: - 静态栈:核心是数组,类似于一个连续内存的数组,区别在于只能操作其顶元素;
- 静态栈:核心是链表,类似于一个不连续内存的有序存放的链表,区别在于只能操作其顶节点。
静态栈的实现(C++代码)
///
/// @file Stack.cc
/// @date 2019-02-08 21:17:08
///
#include <iostream>
using std::cout;
using std::endl;
class Stack
{
public:
Stack(int size)//初始化
:_top(-1)
,_size(size)
,_arr(new int[_size]())
{
cout << "------" << endl;
}
bool full() //判满
{
return _top == _size - 1;
}
bool empty() //判空
{
return _top == -1;
}
void push(const int & val) //压栈
{
if(!full())
{
_arr[++_top] = val;
}else
{
cout << "arry full" << endl;
}
}
void pop()//出栈
{
if(!empty())
{
_top--;
}else
{
cout << "stack empty" << endl;
}
}
int top()//查看顶元素
{
return _arr[_top];
}
int arr_idx() //查看当前栈的长度
{
return (_top+1);
}
private:
int _top;
int _size;
int * _arr;
};
//main用来测试各个方法
int main(void)
{
Stack st1(10);
cout << "empty? " << st1.empty() << endl;
st1.push(1);
cout << "empty? " << st1.empty() << endl;
for(int idx = 2; idx != 12; ++idx)
{
st1.push(idx);
}
cout << "full? " << st1.full() << endl;
cout << "st1.arr_idx = " << st1.arr_idx() << endl;
cout << "st1.top(): " << st1.top() << endl;
st1.pop();
cout << "after pop(): ";
cout << "st1.top(): " << st1.top() << endl;
while(!st1.empty())
{
cout << "top number: " << st1.top() << endl;
st1.pop();
}
return 0;
}
动态栈的实现(C++代码)
动态栈与静态栈相比没有判满操作,因为动态栈对存放元素的数量没有规定。
///
/// @file linkStack.cc
/// @date 2019-02-09 14:56:22
///
#include <iostream>
using std::cout;
using std::endl;
class Node{
public:
Node( Node * pnext, int num)
:_pnext(pnext)
,_num(num)
{
}
Node * retNode()
{
return _pnext;
}
int num()
{
return _num;
}
private:
Node * _pnext;
int _num;
};
class Stack
{
public:
// Stack()
// :_top(NULL)
// ,_length(0)
// {}
Stack(const int num) //初始化
:_node(new Node(NULL,num))
,_top(_node)
,_length(1)
{
}
void push(const int num)//压栈
{
Node * pnode = new Node(_top,num);
_top = pnode;
_length++;
}
void pop()//出栈
{
if(_length > 0)
{
Node * temp = _top;
_top = temp->retNode();
delete temp;
_length--;
}else{
cout << "栈已空" << endl;
}
}
bool empty()
{
return _length;
}
int size()
{
return _length;
}
void clear()
{
while(_length)
{
pop();
}
cout << "已经清空" << endl;
}
int topnum()
{
return _top->num();
}
private:
Node * _node;
Node * _top;
int _length;
};
int main()
{
Stack st1(1);
for(int idx = 2; idx < 13; idx++)
{
st1.push(idx);
}
cout << "top num: " << st1.topnum() << endl;
cout << "st1 size: " << st1.size() << endl;
while(st1.empty())
{
cout << "topnum: " << st1.topnum() << endl;
st1.pop();
}
st1.push(12);
cout << "Is empty: " << st1.empty() << endl;
st1.clear();
cout << "Is empty: " << st1.empty() << endl;
return 0;
}
队列的原理与实现
队列(Queue)与栈一样,是一种线性存储结构,它具有如下特点:
-
队列中的数据元素遵循“先进先出”(First In First Out)的原则,简称FIFO结构;
-
在队尾添加元素,在队头删除元素;
其结构示意图如下(图二):
队列的相关概念: -
队头与队尾: 允许元素插入的一端称为队尾,允许元素删除的一端称为队头;
-
入队:队列的插入操作;
-
出队:队列的删除操作;
队列的操作:
- 入队: 通常命名为push()
- 出队: 通常命名为pop()
- 求队列中元素个数
- 判断队列是否为空
- 获取队首元素
队列的分类: - 基于数组的循环队列(循环队列)
- 基于链表的队列(链队列)
C++代码实现数组循环队列
///
/// @file Queue.cc
/// @date 2019-02-08 21:53:27
///
#include <iostream>
using std::cout;
using std::endl;
class Queue
{
public:
Queue(int size)
:_size(size)
,_front(0)
,_rear(0)
,_arr(new int[_size]())
{}
~Queue()
{
delete [] _arr;
}
bool full() const
{
return (_rear%_size)-(_front%_size) == (_size -1);
}
bool empty() const
{
return (_rear%_size) == (_front%_size);
}
void push(const int & val)
{
if(!full())
{
_rear = _rear%_size;
_arr[_rear++] = val;
}else{
cout << "queue is full" << endl;
}
}
void pop()
{
if(!empty())
{
_front = _front%_size;
_front++;
}else{
cout << "queue is empty " << endl;
}
}
int length()
{
return (_rear%_size)-(_front%_size);
}
int & getFront()
{
return _arr[_front];
}
private:
int _size;
int _front;
int _rear;
int * _arr;
};
int main()
{
Queue que1(6);
for(int idx = 1; idx < 7; idx++)
{
que1.push(idx);
}
cout << "Is full? " << que1.full() << endl;
cout << que1.getFront() << endl;
cout << "empoty? " << que1.empty() << endl;
while(!que1.empty())
{
cout << "_rear num: " << que1.getFront() << endl;
que1.pop();
}
cout << "Is empty: " << que1.empty() << endl;
return 0;
}
C++实现链表队列
///
/// @file linQueue.cc
/// @author XuHuanhuan(1982299154@qq.com)
/// @date 2019-02-09 19:26:39
///
#include <iostream>
using std::cout;
using std::endl;
class Node
{
public:
Node(Node * front, int num)
:_front(front)
,_num(num)
{
}
int retNum()
{
return _num;
}
void putFront(Node * rhs)
{
_front = rhs;
}
Node * retFront()
{
return _front;
}
private:
Node *_front;
int _num;
};
class Queue
{
public:
Queue()
{}
Queue(const int num)
:_que_front(NULL)
,_que_rear(NULL)
,_que_cur(new Node(_que_front,num))
,length(1)
{
_que_front = _que_cur;
_que_rear = _que_cur;
}
void push(const int num)
{
_que_cur = new Node(NULL,num);
_que_front->putFront(_que_cur);
_que_front = _que_cur;
length++;
}
void pop()
{
if(length > 0)
{
Node * temp = _que_rear;
_que_rear = _que_rear->retFront();
delete temp;
length--;
}else{
cout << "队列为空" << endl;
}
}
bool empty()
{
return length;
}
int retNum()
{
return _que_rear->retNum();
}
private:
Node * _que_front;
Node * _que_rear;
Node * _que_cur;
int length;
};
int main()
{
Queue que1(1);
for(int idx = 2; idx < 13; idx++)
{
que1.push(idx);
}
while(que1.empty())
{
cout << "topnum: " << que1.retNum() << endl;
que1.pop();
}
que1.push(12);
cout << "Is empty: " << que1.empty() << endl;
return 0;
}
利用Viso辅助思考可以很快的想清楚各个节点的指针该如何操作
单例模式的原理与实现
单例模式要求该类只能生成唯一的对象,所以该对象不能是栈对象,只能是堆对象。所以,单例模式在技术上就是说要创建一个类该类只能在堆中创建且只能被创建一对象。
示例代码如下:
///
/// @file Singleton.cc
/// @date 2019-02-10 14:20:54
///
#include <stdio.h>
#include <iostream>
using std::cout;
using std::endl;
class Singleton
{
public:
static Singleton * getInstance()
{
if(_pInstance == NULL) //通过static变量_pInstance的判断能够创建唯一的对象
_pInstance = new Singleton();
return _pInstance;
}
private:
Singleton(){}//将构造函数放到private中就可以避免栈对象和堆对象的创建
static Singleton * _pInstance;
};
Singleton * Singleton::_pInstance = NULL;
//Singleton s3;
int main(void)
{
//Singleton s1;//禁止该语句运行, 让其不能通过编译
//Singleton s2;//需要在类之外调用默认构造函数
//Singleton * p1 = new Singleton;
//Singleton * p2 = new Singleton;
Singleton * p1 = Singleton::getInstance();
Singleton * p2 = Singleton::getInstance();
Singleton * p3 = Singleton::getInstance();
printf("p1 = %p\n", p1);
printf("p2 = %p\n", p2);
printf("p3 = %p\n", p3);
delete p1;//不希望该语句编译通过
return 0;
}