C++算法系列-棧與隊列

在學完鏈表後,接下來我們就開始學習棧和隊列了,因爲棧與隊列的實現是基於鏈表的(也可以是數組),所以要先學鏈表,然後緊接着學棧與隊列。


一. 棧(鏈表實現)

1. 棧的簡介
  1. 在生活中,我們會碰到這樣一種情況,在往球桶裏面放球的時候,最先放進去的球,只能在最後取出。
  2. 爲了模擬上述的情況,於是就出現了棧這種數據結構。
  3. 一般棧可以就行如下操作
    1. 入棧push,往棧裏面存放元素。
    2. 出棧pop,取出棧的頂部元素。
    3. 清空棧pop_all,將棧裏面的全部元素都出棧。
    4. 判斷棧是否爲空。
    5. 返回棧的頂部元素,但不出棧。
2. 棧的實現
  1. 入棧
void push(int i)
	{
		Node* q = new Node;
		q->data = i;
		if (tail != NULL)
		{
			q->next = tail;
			tail = q;
		}
		else
		{
			
			tail = q;
			q->next = NULL;
		}
	}
  1. 出棧
bool pop()
	{
		if (tail != NULL)
		{
			Node*q = tail;
			tail = tail->next;
			delete q;
			return true;
		}
		else
			return false;
	}
  1. 判斷棧是否爲空
bool empty()
	{
		if (tail != NULL)
			return false;
		else
			return true;
	}
  1. 返回頂部元素
int top()
	{
		if (tail != NULL)
			return tail->data;
		else
			return 0;
	}
  1. 清空棧
void pop_all()
	{
		Node * p = tail, *q;
		while (p->next)
		{
			q = p->next;
			delete p;
			p = q;
		}
		delete p;
		tail = NULL;
		
	}
  1. 完整實現
#include<iostream>

using namespace std;

class Node
{
public:
	int data;
	Node *next;
};

class Stack {
private:
	Node  *tail;

public:
	Stack()
	{
		tail = NULL;
	}
	Stack(int i)
	{
		Node *q = new Node;
		q->data = i;
		tail = q;
		q->next = NULL;
	}
	~Stack()
	{
		Node * p = tail, *q;
		while (p)
		{
			q = p->next;
			delete p;
			p = q;
		}
		delete p;
		
	}
	//入棧
	void push(int i)
	{
		Node* q = new Node;
		q->data = i;
		if (tail != NULL)
		{
			q->next = tail;
			tail = q;
		}
		else
		{
			
			tail = q;
			q->next = NULL;
		}
	}
	//出棧
	bool pop()
	{
		if (tail != NULL)
		{
			Node*q = tail;
			tail = tail->next;
			delete q;
			return true;
		}
		else
			return false;
	}
	//返回頂部元素
	int top()
	{
		if (tail != NULL)
			return tail->data;
		else
			return 0;
	}
	//判斷棧是否爲空
	bool empty()
	{
		if (tail != NULL)
			return false;
		else
			return true;
	}
	//清空棧
	void pop_all()
	{
		Node * p = tail, *q;
		while (p->next)
		{
			q = p->next;
			delete p;
			p = q;
		}
		delete p;
		tail = NULL;
		
	}
};


二. 隊列

1. 隊列簡介
  1. 在日常中,我們又會遇到另外一種非常常見的情況,那就是排隊。在排隊的時候,最先來的,業務就可以就先處理完。
  2. 在這種情況下,我們就使用隊列這種數據結構來模擬這種情況。
  3. 隊列一般可以進行的操作。
    clear清空隊列
    isEmpty判斷隊列是否爲空
    enqueue在隊列尾部加入元素
    dequeue取出隊列的第一個元素
    firstE返回隊列的第一個元素,但不刪除
2. 隊列的實現
  1. 完整代碼,基於庫中的列表
#include<list>

template<class T>
class Queue {
private:
	list<T> lst;
public:
	Queue()
	{
	}
	void clear()
	{
		lst.clear();
	}
	bool isEmpty() const {
		return lst.empty();
	}
	T& front()
	{
		return lst.front();
	}
	T dequeue()
	{
		T e1 = lst.front();
		lst.pop_front();
		return e1;
	}
	void enqueue(const T& e1)
	{
		lst.push_back(e1);
	}
};

三. 課後習題

  1. 將棧S中的元素的順序倒過來
    1-a 使用兩個額外的棧
int main()
{
	stack<int > q1;
	stack<int > q2;
	stack<int > q3;

	q1.push(1);
	q1.push(2);
	q1.push(3);
	
	
	q2.push(q1.top());
	q1.pop();
	q2.push(q1.top());
	q1.pop();
	q2.push(q1.top());
	q1.pop();

	q3.push(q2.top());
	q2.pop();
	q3.push(q2.top());
	q2.pop();
	q3.push(q2.top());
	q2.pop();

	q1.push(q3.top());
	q3.pop();
	q1.push(q3.top());
	q3.pop();
	q1.push(q3.top());
	q3.pop();

	while (!q1.empty())
	{
		cout << q1.top();
		q1.pop();
	}

	return 0;
}

1-b 使用額外的一個隊列

int main()
{
	stack<int> q;
	list<int> m;

	q.push(1);
	q.push(2);
	q.push(3);

	while (!q.empty())
	{
		m.push_back(q.top());
		q.pop();
	}
	while (!m.empty())
	{
		q.push(m.front());
		m.pop_front();
	}
	while (!q.empty())
	{
		cout << q.top();
		q.pop();
	}
	return 0;
}

1-c 使用額外的一個棧和幾個額外的非數組變量

int main()
{
	stack<int> q;
	stack<int> q2;
	
	q.push(1);
	q.push(2);
	q.push(3);

	while (!q.empty())
	{
		q2.push(q.top());
		q.pop();
	}
	q.swap(q2);
	while (!q.empty())
	{
		cout << q.top();
		q.pop();
	}
}
  1. 使用一個額外的棧和幾個額外的非數組變量,將棧S中的元素按升序排列
int main()
{
	stack<int> q;
	stack<int> q2;
	int a=0, b=0,c = -10, min = 9999;

	q.push(2), q.push(5), q.push(1),q.push(4),q.push(7),q.push(10),q.push(8),q.push(3);
	for (int i = 0; i < 7; i++)
	{
		min = 999;
		while (!q.empty())
		{
			if (q.top() == c)
				break;
			if (q.top() < min)
				min = q.top();
			q2.push(q.top());
			q.pop();
		}
		c =min;
		q.push(min);
		while (!q2.empty())
		{
			
			if (q2.top() == min)
			{
				q2.pop();
				continue;
			}
			q.push(q2.top());
			q2.pop();
			
		}
		b = 0;
	}
	while (!q.empty())
	{
		cout << q.top()<<" ";
		q.pop();

	}
	return 0;
}
  1. 將棧S1中的元素轉換到棧S2中,使S2中元素的順序與S1中元素的順序相同
    3-a 使用一個額外的棧
int main()
{
	stack<int> S1;
	stack<int> S2;
	stack<int> q;

	S1.push(2), S1.push(3), S1.push(4), S1.push(5);

	while (!S1.empty())
	{
		q.push(S1.top());
		S1.pop();
	}
	while (!q.empty())
	{
		S2.push(q.top());
		q.pop();
	}
	while (!S2.empty())
	{
		cout << S2.top() << " ";
		S2.pop();
	}
	return 0;
}

3-b 不使用額外的棧,只使用幾個額外的非數組變量

int main()
{
	stack<int> S1, S2;
	int a, b=0, c = 1, d;
	S1.push(1);
	S1.push(2);
	S1.push(3);
	S1.push(4);
	a = S1.size();
	
	while (a)
	{
		// 寫出 i<S1.size() - 1 會出現錯誤
		for (int i = 0; i <a - c; i++)
		{
			
			S2.push(S1.top());
			S1.pop();
		}
		d = S1.top();
		
		S1.pop();
		for (int i = 0; i < 3-b; i++)
		{
			S1.push(S2.top());
			S2.pop();
		}
		S2.push(d);
		b++;
		a--;	
	}
	
	while (!S2.empty())
	{
		cout << S2.top() << " ";
		S2.pop();
	}

	return 0;
}
  1. 使用額外的非數組變量及下面的條件,將隊列中的所有元素排序
    5-a 兩個額外的隊列
int main()
{
	queue<int> q1 , q2, q3;
	q1.push(4), q1.push(1), q1.push(7), q1.push(10), q1.push(2), q1.push(6), q1.push(8);
	int min;
	int a = q1.size();
	
	for (int i = 0; i < a; i++)
	{
		min = 999;
		while (!q1.empty())
		{
			if (q1.front() < min)
			{
				min = q1.front();
			}
			q2.push(q1.front());
			q1.pop();
		}
		while (!q2.empty())
		{
			if (q2.front() == min)
			{
				q2.pop();
				continue;
			}
			q1.push(q2.front());
			q2.pop();

		}	
		q3.push(min);

	}
	
	while (!q3.empty())
	{
		cout << q3.front()<<" " ;
		q3.pop();
	}
	return 0;
}

以上就是棧和隊列的大部分內容。
ps:以上知識學習於《C++數據結構與算法》Adam Drozdek 著, 徐丹,吳偉敏 譯。
Thank for your reading !!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章