【劍指offer】兩個佇列實現一個棧

蘭亭風雨發表於2014-05-06

轉載請註明出處:http://blog.csdn.net/ns_code/article/details/25076689


    題目:用兩個佇列模擬一個棧,即用兩個佇列的出隊和入隊操作,來實現棧的出棧和入棧操作。

    思路:稍微畫下草圖,便不難想出該題的解決方法,思路如下:

    假設有兩個佇列Q1和Q2,當二者都為空時,入棧操作可以用入隊操作來模擬,可以隨便選一個空佇列,假設選Q1進行入棧操作,現在假設a,b,c依次入棧了(即依次進入佇列Q1),這時如果想模擬出棧操作,則需要將c出棧,因為在棧頂,這時候可以考慮用空佇列Q2,將a,b依次從Q1中出隊,而後進入佇列Q2,將Q1的最後一個元素c出隊即可,此時Q1變為了空佇列,Q2中有兩個元素,隊頭元素為a,隊尾元素為b,接下來如果再執行入棧操作,則需要將元素進入到Q1和Q2中的非空佇列,即進入Q2佇列,出棧的話,就跟前面的一樣,將Q2除最後一個元素外全部出隊,並依次進入佇列Q1,再將Q2的最後一個元素出隊即可。

    實現程式碼如下:

/*
用兩個佇列模擬入棧操作
*/
void push(PQUEUE pS1,PQUEUE pS2,int val)
{
	if(is_empty(pS2))
		en_queue(pS1, val);
	else
		en_queue(pS2, val);
}

/*
用兩個佇列模擬出棧操作
*/
bool pop(PQUEUE pS1,PQUEUE pS2,int *pData)
{
	if(is_empty(pS1) && is_empty(pS2))
		return false;

	int DelData;
	if(!is_empty(pS2))
	{
		int len = length(pS2);
		while(len-- > 1)
		{
			de_queue(pS2,&DelData);
			en_queue(pS1,DelData);
		}
		//將佇列的最後一個元素出隊,作為出棧元素
		de_queue(pS2,pData);
		return true;
	}
	if(!is_empty(pS1))
	{
		int len = length(pS1);
		while(len-- > 1)
		{
			de_queue(pS1,&DelData);
			en_queue(pS2,DelData);
		}
		//將佇列的最後一個元素出隊,作為出棧元素
		de_queue(pS1,pData);
		return true;
	}
}

    完整的程式碼(用的以前寫的鏈式佇列)如下:

/*******************************************************************
題目:用兩個佇列模擬一個棧
*******************************************************************/

#include<stdio.h>
#include<stdlib.h>

typedef struct Node
{
	int data;
	struct Node *pNext;
}NODE,*PNODE;

typedef struct Queue
{
	PNODE front;  //隊頭指標
	PNODE rear;   //隊尾指標
}QUEUE,*PQUEUE;

PQUEUE create_queue();
bool is_empty(PQUEUE);
void en_queue(PQUEUE, int);
bool de_queue(PQUEUE,int *);
void destroy_queue(PQUEUE);
void traverse_queue(PQUEUE);
int length(PQUEUE);
void push(PQUEUE,PQUEUE,int);
bool pop(PQUEUE,PQUEUE,int *);

int main()
{
	int pData;         //用來儲存出隊的元素值

	//建立佇列並進行入隊測試
	PQUEUE pS1 = create_queue();
	PQUEUE pS2 = create_queue();
	push(pS1,pS2,4);
	push(pS1,pS2,5);
	printf("the length of pS1: %d\n",length(pS1));
	printf("the length of pS2: %d\n",length(pS2));
	if(pop(pS1,pS2,&pData))
		printf("%d is pop out\n",pData);
	else
		printf("Stack is empty,can not pop\n");
	printf("the length of pS1: %d\n",length(pS1));
	printf("the length of pS2: %d\n",length(pS2));
	push(pS1,pS2,6);
	printf("the length of pS1: %d\n",length(pS1));
	printf("the length of pS2: %d\n",length(pS2));
	push(pS1,pS2,7);
	printf("the length of pS1: %d\n",length(pS1));
	printf("the length of pS2: %d\n",length(pS2));
	if(pop(pS1,pS2,&pData))
		printf("%d is pop out\n",pData);
	else
		printf("Stack is empty,can not pop\n");
	printf("the length of pS1: %d\n",length(pS1));
	printf("the length of pS2: %d\n",length(pS2));	
	if(pop(pS1,pS2,&pData))
		printf("%d is pop out\n",pData);
	else
		printf("Stack is empty,can not pop\n");
	printf("the length of pS1: %d\n",length(pS1));
	printf("the length of pS2: %d\n",length(pS2));
	if(pop(pS1,pS2,&pData))
		printf("%d is pop out\n",pData);
	else
		printf("Stack is empty,can not pop\n");
	printf("the length of pS1: %d\n",length(pS1));
	printf("the length of pS2: %d\n",length(pS2));
	if(pop(pS1,pS2,&pData))
		printf("%d is pop out\n",pData);
	else
		printf("Stack is empty,can not pop\n");

	return 0;
}

/*
建立一個空佇列,隊頭指標和隊尾指標都指向頭結點,
頭結點中不存放資料,只存放指標
*/
PQUEUE create_queue()
{
	PQUEUE pS = (PQUEUE)malloc(sizeof(Queue));
	pS->front = (PNODE)malloc(sizeof(NODE));
	if(!pS || !pS->front)
	{
		printf("pS or front malloc failed!!");
		exit(-1);
	}
	else
	{
		pS->rear = pS->front;
		pS->front->pNext = NULL;
	}
	return pS;
}

/*
判斷佇列是否為空
*/
bool is_empty(PQUEUE pS)
{
	if(pS->front == pS->rear)
		return true;
	else
		return false;
}

/*
進隊函式,從隊尾進隊,隊頭指標保持不變
*/
void en_queue(PQUEUE pS, int e)
{
	PNODE pNew = (PNODE)malloc(sizeof(NODE));
	if(!pNew)
	{
		printf("pNew malloc failed");
		exit(-1);
	}
	else
	{
		pNew->data = e;
		pNew->pNext = NULL;
		pS->rear->pNext = pNew;
		pS->rear = pNew;
	}
	return;
}

/*
出隊函式,從隊頭出隊,隊尾指標保持不變,但當最後一個元素出隊時,
需要對隊尾指標重新賦值,使其指向頭結點
*/
bool de_queue(PQUEUE pS,int *pData)
{
	if(is_empty(pS))
		return false;
	else
	{
		PNODE p = pS->front->pNext;
		*pData = p->data;
		pS->front->pNext = p->pNext;

		//這裡是佇列頭元素出隊的特殊情況,一般情況下,刪除隊頭元素時
		//僅需修改頭結點中的指標,但當佇列中最後一個元素被刪除時,
		//佇列尾指標也丟失了,因此需對隊尾指標重新賦值(指向頭結點)。
		if(pS->rear == p)         
			pS->rear = pS->front;
		free(p);
	}
	return true;
}

/*
遍歷佇列,從對頭向隊尾依次輸出隊中的元素
*/
void traverse_queue(PQUEUE pS)
{
	if(is_empty(pS))
		printf("there is no data in the queue!\n");
	else
	{	
		PNODE pCurrent = pS->front->pNext; 
		printf("Now datas int the queue are:\n");
		while(pCurrent)
		{
			printf("%d ",pCurrent->data);
			pCurrent = pCurrent->pNext;
		}
		printf("\n");
	}
	return;
}

/*
求佇列的長度
*/
int length(PQUEUE pS)
{
	int count = 0;
	PNODE pCurrent = pS->front->pNext; 
	while(pCurrent)
	{
		count++;
		pCurrent = pCurrent->pNext;
	}
	return count;
}

/*
銷燬佇列,頭結點也被銷燬,最後也將pS節點銷燬,並將其指向為空,避免垂直指標的產生
*/
void destroy_queue(PQUEUE pS)
{
	if(is_empty(pS))
		return;
	else
	{
		while(pS->front)
		{
			pS->rear = pS->front->pNext;
			free(pS->front);
			pS->front = pS->rear;
		}
	}
	free(pS);
	pS = 0;
	return;
}

/*
用兩個佇列模擬入棧操作
*/
void push(PQUEUE pS1,PQUEUE pS2,int val)
{
	if(is_empty(pS2))
		en_queue(pS1, val);
	else
		en_queue(pS2, val);
}

/*
用兩個佇列模擬出棧操作
*/
bool pop(PQUEUE pS1,PQUEUE pS2,int *pData)
{
	if(is_empty(pS1) && is_empty(pS2))
		return false;

	int DelData;
	if(!is_empty(pS2))
	{
		int len = length(pS2);
		while(len-- > 1)
		{
			de_queue(pS2,&DelData);
			en_queue(pS1,DelData);
		}
		//將佇列的最後一個元素出隊,作為出棧元素
		de_queue(pS2,pData);
		return true;
	}
	if(!is_empty(pS1))
	{
		int len = length(pS1);
		while(len-- > 1)
		{
			de_queue(pS1,&DelData);
			en_queue(pS2,DelData);
		}
		//將佇列的最後一個元素出隊,作為出棧元素
		de_queue(pS1,pData);
		return true;
	}
}

    測試結果:



相關文章