1. 程式人生 > >棧排序(空間複雜度O(1))

棧排序(空間複雜度O(1))

如果要將空間複雜度為O(1),那麼就不能夠宣告陣列來申請空間了

只有兩個堆疊可以使用。

那麼我們該怎麼去實現排序了,因為堆疊是後進先出,只有一端能進入和出去,這就使得問題複雜了。

其實我們可以不再另申請空間也能完成排序。

比如,一個輸出棧S,輸入棧R,我們每次將輸入棧的元素push進入輸出棧S,但是因為我們的輸出棧元素需要排序,假定從棧底到棧頂按照從小到大的順序排列,那麼我們如果輸入的棧的元素比輸出棧中的棧頂元素小,按理說,應該排在這個棧頂元素的下面。所以,我們這時候需要先將輸出棧中的棧頂元素pop出來,然後再將輸入棧的棧頂元素push進入輸入棧,這時候我們在將之前pop出來的棧頂元素在按照原有的排序push進入輸出棧。

那麼,問題是我們將輸出棧中pop出去的那一部分元素怎麼儲存呢,當然,通常情況下我們可以使用陣列儲存啊,但是空間複雜度為O(1)的時候,很顯然我們不能在定義陣列申請空間,其實我們可以將pop出去的元素push進入輸入棧的棧頂,等之前輸入棧push進入輸出棧的元素找到位置後,再依次push到輸出棧,這樣既可以不開闢空間,也可以完成棧的排序。

例:

棧排序
時間限制:1 sec

空間限制:256 MB

問題描述
給定一個序列 A,請你將它升序排序。

輸入格式
第一行一個正整數 n,表示序列長度。

第二行 n 個用空格隔開的非負整數,描述這個序列。

輸出格式
n 行,每行一個非負整數,表示排序後的序列。

樣例輸入
4
1 3 2 10
樣例輸出
1
2
3
10
資料範圍
保證 n<=1000,保證序列中的數不超過 32767,以及時間複雜度為O(1)

我們其實就可以使用剛剛說的方法,藉助輸入棧存放一些元素的方法。

程式碼:因為輸出要求是升序輸出,我這裡用的棧排序是降序壓進棧中。所以我這裡使用的輸出方式是vector逆迭代器

#include<iostream>
#include<stack>
#include<vector>

using namespace std;

stack<int> Stack_Sort(stack<int> myStack)
{ 
	stack<int> output;     //最後需要輸出的堆疊 
	
	if(myStack.empty())   //輸入堆疊為空 ,若為空,就沒有元素壓入棧中 
	  return output;
	
	int t = myStack.top();  //要壓入output的元素
	
	
	myStack.pop();  //彈出元素 
	
	//! myStack.empty()這是一個邊界條件,意味著輸入棧的元素壓完後,就結束排序操作了
	// (!output.empty() && output.top()>t) 這一個式子有一點複雜
	// !output.empty()如果輸出棧為空或者是 output.top()>t輸出棧棧頂指標比最後的t(存放的是輸入棧所有元素壓完進入輸出棧,但是t變數還是存了一個元素) 
	//然後我們必須把t在壓入輸出棧中,但是因為會考慮到亂序,那麼通過 output.top()>t考慮到是否再重新排序 
	while(!myStack.empty() || (!output.empty() && output.top()>t))
	{
		if(output.empty() || output.top()<=t)
		{
			output.push(t);
			t = myStack.top();   //更新元素 
			myStack.pop();
		}
		else
		{
			myStack.push(output.top());
			output.pop();
		}
	} 
	output.push(t);
	return output;
}


int main()
{
	
	stack<int> R;    //亂序的堆疊,將從該堆疊一直pop元素到堆疊S 
	int nums;
	int n;
	cin>>n;
	for(int i = 1;i<n;i++)
	{
		cin>>nums;
		R.push(nums);
	} 
	
	stack<int> result = Stack_Sort(R);
	
	vector<int> answer;   
	
    while(!result.empty())
    {
    	answer.push_back(result.top());  //將堆疊裡的內容從尾部一個一個新增到vector 
    	result.pop();
    }
    //反向迭代器 ,因為我們需要輸出升序,就需要將容器逆序輸出 
    for(vector<int>::reverse_iterator i = answer.rbegin();i!=answer.rend();++i)
    {
    	cout<<*i<<endl;
    }
     
	
	return 0;
}

這裡的輸出邊pop()邊輸出,便於理解

#include<iostream>
#include<stack>
using namespace std;

stack<int> Stack_sorting(stack<int> input)
{
	stack<int> output;
	
	if(input.empty())
	return output;
	
	int temp = input.top();
	input.pop();
	
	while(!input.empty() || (!output.empty() && output.top()>temp))
	{
		if(output.empty() || output.top()<=temp)
		{
			output.push(temp);
			temp = input.top();
			input.pop();
		}
		else
		{
			input.push(output.top());
			output.pop();
		}
	}
	output.push(temp);
	return output;
}

int main()
{
	stack<int> R;  //輸入棧
	int n;
	int nums;
	cin>>n;
	
	for(int i = 0;i<n;i++)
	{
		cin>>nums;
		R.push(nums);
	} 
	
	stack<int> reslut = Stack_sorting(R);
	stack<int> fuzhu;
	
	for(int j = 0;j<n;j++)
	{
		fuzhu.push(reslut.top());
		reslut.pop();
	}
	
	for(int k = 0;k<n;k++)
	{
		cout<<fuzhu.top()<<endl;
		fuzhu.pop();
	}
	
	return 0;
}