概念
1.图的深度优先遍历(DFS)
可以用栈实现,从根结点开始沿左孩子到最深的节点压入栈中,然后依次弹出,若栈顶节点还有没有访问的孩子,则没访问过得孩子入栈直到最深的节点,然后再弹出。元素入栈顺序则为深度优先遍历顺序。
2.图的宽度优先遍历(BFS)
可以用队列实现,将根结点放入队列,每弹出一个节点,就将该节点的孩子全部放入队列,放入队列的顺序为宽度优先遍历顺序。
示例一
实现一个特殊的栈,在实现栈的基础功能的基础上,再实现返回栈中最小元素的操作getMin。
要求:1.pop,push,getMin操作的时间复杂度都为
O
(
1
)
O(1)
O(1)。
2.设计的栈类型可以使用现成的栈结构。
分析:
思路一:构造两个栈,一个stackData存储数据,一个stackMin存储当前的最小值,只有当前数小于等于stackMin的栈顶元素时,该数放入stackMin中,否则不压入,当弹出时,若stackData栈顶等于stackMin时,stackMin才弹出,否则不弹出。
template <typename T> class newStack {
public:
std::stack<T> stackData;
std::stack<T> stackMin;
void push(T data) {
stackData.push(data);
if (stackMin.empty())
{
stackMin.push(data);
}
else
{
if (data <= stackMin.top()) {
stackMin.push(data);
}
}
}
void pop() {
if (!stackData.empty()) {
if (stackData.top() == stackMin.top()) {
stackMin.pop();
}
stackData.pop();
}
}
T top();
T getMin();
bool empty();
};
template <typename T> T newStack<T>::top() {
return stackData.top();
}
template <typename T> T newStack<T>::getMin() {
return stackMin.top();
}
template <typename T> bool newStack<T>::empty() {
return stackData.empty();
}
思路二:构造两个栈,一个stackData存储数据,一个stackMin存储当前的最小值,每次压入数据时两个栈都压入,stackData压入给定数据,stackMin压入给定数据或stackMin栈顶元素较小的那个,弹出时两个栈一起弹出。
template <typename T> class newStack {
public:
std::stack<T> stackData;
std::stack<T> stackMin;
void push(T data);
void pop();
T top();
T getMin();
bool empty();
};
template <typename T> void newStack<T>::push(T data) {
stackData.push(data);
if (stackMin.empty()) {
stackMin.push(data);
}
else {
if (stackMin.top() >= data) {
stackMin.push(data);
}
else{
stackMin.push(stackMin.top());
}
}
}
template <typename T> void newStack<T>::pop() {
if (!stackData.empty()) {
stackData.pop();
stackMin.pop();
}
}
template <typename T> T newStack<T>::top() {
return stackData.top();
}
template<typename T> T newStack<T>::getMin() {
return stackMin.top();
}
template<typename T> bool newStack<T>::empty() {
return stackData.empty();
}
示例二
编写一个类,只能用两个栈结构实现队列,支持队列的基本操作(add,poll,peek)。
分析:一个栈stackPush用来放入,一个栈stackPop用来弹出。放数据的时候直接放到stackPush中,弹出时,若stackPop不为空,直接弹出,若为空且stackPush不为空,则将stackPush数据依次弹出压入stackPop后再从stackPop中弹出。
#include<iostream>
#include<stack>
#include<thread>
using std::cout;
using std::endl;
template <typename T> class newQueue {
private:
std::stack<T> stackPush;
std::stack<T> stackPop;
public:
void add(T data) {
stackPush.push(data);
}
void poll() {
if (!stackPop.empty()) {
stackPop.pop();
}
else{
if (!stackPush.empty()) {
while (!stackPush.empty()){
stackPop.push(stackPush.top());
stackPush.pop();
}
}
}
}
T peek() {
if (!stackPop.empty()) {
return stackPop.top();
}
else {
if (!stackPush.empty()) {
while (!stackPush.empty()) {
stackPop.push(stackPush.top());
stackPush.pop();
}
return stackPop.top();
}
else {
throw;
}
}
}
bool empty() {
return stackPop.empty() && stackPush.empty();
}
};
int main(void) {
newQueue<int> queueK;
queueK.add(1);
queueK.add(2);
queueK.add(3);
while (!queueK.empty()){
cout << queueK.peek() << endl;
queueK.poll();
}
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
示例三
实现一个栈的逆序,但是只能用递归函数和这个栈本身的操作来实现,而不能自己申请另外的数据结构。
分析:构造两个函数
1.移除栈底元素并返回
2.回归取空栈并放入当前取出的栈底
#include<iostream>
#include<stack>
#include<thread>
using std::cout;
using std::endl;
template<typename T> T getBottom(std::stack<T> &stackR) {
if (stackR.empty()) {
return NULL;
}
T nowData = stackR.top();
stackR.pop();
if (stackR.empty()) {
return nowData;
}
T lastData = getBottom(stackR);
stackR.push(nowData);
return lastData;
}
template<typename T> void reverseStack(std::stack<T> &stackR) {
if (stackR.empty()) {
return;
}
T nowData = getBottom(stackR);
reverseStack(stackR);
stackR.push(nowData);
}
int main(void) {
std::stack<int> st;
st.push(1);
st.push(2);
st.push(3);
st.push(4);
reverseStack(st);
while (!st.empty()){
cout << st.top() << endl;
st.pop();
}
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
示例四
一个栈中元素类型为整形,现在将该栈从顶到底按从大到小排序,只许申请一个栈,除此之外可以申请新的变量,但不能申请额外的数据结构。如何完成排序。
分析:临时申请一个栈helpStack,当Stack中的栈顶current小于等于helpStack栈顶时,将current从Stack中弹压入helpStack,若大于,则将helpStack栈中元素弹出压入Stack中,直到current 小于等于helpStack栈顶元素为止。重复上述过程直到Stack中元素全部压入helpStack中。
#include<iostream>
#include<stack>
#include<thread>
using std::cout;
using std::endl;
template<typename T> void sortStack(std::stack<T> &unsortStack) {
auto size = unsortStack.size();
if (size < 2) {
return;
}
std::stack<T> helpStack;
T current = unsortStack.top();
unsortStack.pop();
while(helpStack.size() != size) {
if (helpStack.empty()) {
helpStack.push(current);
current = unsortStack.top();
unsortStack.pop();
}
if (current <= helpStack.top()) {
helpStack.push(current);
if (unsortStack.empty()) {
break;
}
current = unsortStack.top();
unsortStack.pop();
}
else {
unsortStack.push(helpStack.top());
helpStack.pop();
}
}
while (!helpStack.empty()){
unsortStack.push(helpStack.top());
helpStack.pop();
}
}
int main(void) {
std::stack<int> st;
st.push(12);
st.push(7);
st.push(99);
st.push(4);
st.push(2);
st.push(3);
st.push(1);
sortStack(st);
while (!st.empty()){
cout << st.top() << endl;
st.pop();
}
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
示例五
有一个数组arr和一个大小为w的窗口从数组的最左端滑到最右端,窗口每次向右滑一个位置,返回一个长度为n-w+1的数组res,res[i]表示每一种窗口状态下的最大值。如[4, 3, 5, 4, 3, 3, 6, 7],窗口为3,res为[5,5,5,4,6,7]。
分析:时间复杂度可以做到
O
(
N
)
O(N)
O(N).
首先建立一个双向队列qmax记录数组的下标,若当前数为arr[i],放入规则为
1.如果qmax为空,将i放入qmax尾部。
2.如果qmax不为空,qmax队尾下标为j,若arr[i]<arr[j],则将i放入qmax尾部。如果arr[i]>=arr[j],弹出j,重复步骤2,直到arr[i]<arr[j],将i放入qmax尾部。
如果qmax的头j小于等于i-w,则弹出qmax队首元素。
arr[qmax队首]为res[i]。
#include<iostream>
#include<stack>
#include<thread>
#include<vector>
#include<queue>
using std::cout;
using std::endl;
std::vector<int> windowMax(const int *unsortArray, const int &length,const int &window) {
std::vector<int> maxVector;
std::deque<int> helpQueue;
if (length < window) {
return maxVector;
}
int i = 0;
while (i<length){
if (helpQueue.empty()) {
helpQueue.push_back(i);
}
else {
if (unsortArray[i] > unsortArray[helpQueue.back()]) {
helpQueue.pop_back();
}
else {
helpQueue.push_back(i);
while (helpQueue.front()<=(i-window)){
helpQueue.pop_front();
}
if (i >= window - 1) {
maxVector.push_back(unsortArray[helpQueue.front()]);
}
++i;
}
}
}
return maxVector;
}
int main(void) {
int unsortArray[8]={4, 3, 5, 4, 3, 3, 6, 7};
std::vector<int> maxVector;
maxVector = windowMax(unsortArray, 8, 3);
for (auto i = maxVector.begin(); i != maxVector.end(); ++i) {
cout << *i << endl;
}
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 1;
}
示例六
给定一个没有重复元素的数组arr,写出生成这个数组的MaxTree函数,要求如果数组长度为N,则时间复杂度为
O
(
N
)
O(N)
O(N),额外空间复杂度为
O
(
N
)
O(N)
O(N)。MaxTree的概念如下:
1.MaxTree是一颗二叉树,数组的每一个值对应一个二叉树节点。
2.包括MaxTree数在内且其中的每一颗子树上,值最大的节点都是树的头。
分析:记录两个序列,第一个序列leftBigger记录数组arr中每个数左边第一个比当前数大的数,第二个序列rightBigger记录数组arr中每个数右边第一个比当前数大的数。然后比较这两个数组,较小的数为当前数的父节点。
#include<iostream>
#include<thread>
#include<string>
#include<queue>
#include<stack>
using std::cout;
using std::endl;
template<typename T> class BinNode {
public:
T data;
int height = 0;
BinNode<T> *parent = NULL;
BinNode<T> *lc = NULL;
BinNode<T> *rc = NULL;
BinNode() = default;
BinNode(T e, int h, BinNode<T> *pa = NULL, BinNode<T> *lcc = NULL, BinNode<T> *rcc = NULL) :
data(e), height(h), parent(pa), lc(lcc), rc(rcc) {}
static void tranIn(BinNode *node) {
if (!node) {
return;
}
BinNode<T>::tranIn(node->lc);
cout << node->data << endl;
BinNode<T>::tranIn(node->rc);
}
};
template<typename T> std::vector<int> leftBigger(const T *unsortArray, const std::size_t length) {//寻找每个数左边大于当前数的下标
std::stack<T> temStack;
std::vector<int> temVector;
std::size_t i = 0;
while (i < length) {
if (temStack.empty()) {
temVector.push_back(-1);
temStack.push(i);
++i;
}
else {
if (unsortArray[i] > unsortArray[temStack.top()]) {
temStack.pop();
}
else {
temVector.push_back(temStack.top());
temStack.push(i);
++i;
}
}
}
return temVector;
}
template<typename T> std::vector<int> rightBigger(const T *unsortArray, const std::size_t length) {
std::stack<T> temStack;
std::vector<int> temVector;
int i = length - 1;
while (i >= 0) {
if (temStack.empty()) {
temVector.push_back(-1);
temStack.push(i);
--i;
}
else {
if (unsortArray[i] > unsortArray[temStack.top()]) {
temStack.pop();
}
else {
temVector.push_back(temStack.top());
temStack.push(i);
--i;
}
}
}
return temVector;
}
template<typename T> BinNode<T>* getMaxTree(const T *unsortArray, const int length) {
BinNode<T> *nodes = new BinNode<T>[length];
std::vector<int> lbVector;
std::vector<int> rbVector;
BinNode<T> *maxNode = NULL;
lbVector = leftBigger(unsortArray, length);
rbVector = rightBigger(unsortArray, length);
for (int i = 0; i < length; ++i) {
nodes[i].data = unsortArray[i];
}
for (int i = 0; i < length; ++i) {
if ((lbVector[i] != -1) && (rbVector[length - 1 - i] != -1)) {
if (unsortArray[lbVector[i]] > unsortArray[rbVector[length - 1 - i]]) {
//cout <<"choseR:" <<i << endl;
if (nodes[rbVector[length - 1 - i]].lc == NULL) {
nodes[rbVector[length - 1 - i]].lc = &nodes[i];
}
else{
nodes[rbVector[length - 1 - i]].rc = &nodes[i];
}
}
else {
//cout << "chooseL:" << i << endl;
if (nodes[lbVector[i]].lc == NULL) {
nodes[lbVector[i]].lc = &nodes[i];
}
else {
nodes[lbVector[i]].rc = &nodes[i];
}
}
}
else if (rbVector[length - 1 - i] != -1) {
//cout << "r:" << i << endl;
if (nodes[rbVector[length - 1 - i]].lc == NULL) {
nodes[rbVector[length - 1 - i]].lc = &nodes[i];
}
else {
nodes[rbVector[length - 1 - i]].rc = &nodes[i];
}
}
else if (lbVector[i] != -1) {
//cout << "l:" << i << endl;
if (nodes[lbVector[i]].lc == NULL) {
nodes[lbVector[i]].lc = &nodes[i];
}
else {
nodes[lbVector[i]].rc = &nodes[i];
}
}
else {
//cout << "max:" << i << endl;
maxNode = &nodes[i];
}
}
return maxNode;
}
int main() {
int unsortArry[5] = { 3,4,5,1,2 };
BinNode<int> *tree;
tree = getMaxTree(unsortArry, 5);
cout << "start:"<<endl;
BinNode<int>::tranIn(tree);
while (1)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}