1. 程式人生 > >資料結構與演算法學習--棧

資料結構與演算法學習--棧

在這裡插入圖片描述

1、順序棧的實現:

/*************************************************************************
 > File Name: arrayStack.h
 > Author:  jinshaohui
 > Mail:    [email protected]
 > Time:    18-10-12
 > Desc:    
 ************************************************************************/

#ifndef ARRAY_STACJ_H
#define ARRAY_STACJ_H

typedef struct _array_stack
{
	int size;/*棧的大小*/
	int pos;/*當前儲存元素的個數,即棧頂元素下表*/
	int *array;/*資料儲存區*/
}stArrayStack;

#define arrayStack_size(arrayStack) (arrayStack->size)
#define arrayStack_is_empty(arrayStack) (arrayStack->pos == -1)
#define arrayStack_is_full(arrayStack)  (arrayStack->pos == (arrayStack->size-1))

#endif
/*************************************************************************
 > File Name: arrayStack.c
 > Author:  jinshaohui
 > Mail:    [email protected]
 > Time:    18-10-12
 > Desc:   陣列實現順序棧 
 ************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"./arrayStack.h"

/*建立並初始化順序棧*/
stArrayStack * arrayStack_create(int size)
{
	stArrayStack *parrStack = NULL;

	parrStack = (stArrayStack *)malloc(sizeof(stArrayStack));
	if (parrStack == NULL)
	{
		return NULL;
	}
	
	parrStack->size = size;
	parrStack->pos = -1;
	parrStack->array = (int *)malloc(sizeof(int)*size);
	if(parrStack->array == NULL)
	{
		free(parrStack);
		return NULL;
	}

	return parrStack;
}
/*銷燬順序棧*/
void arrayStack_destory(stArrayStack * parrStack)
{
	if(parrStack == NULL)
	{
		return;
	}

	if (parrStack->array != NULL)
	{
		free(parrStack->array);
	}

	free(parrStack);
	return;
}
/*出棧*/
int arrayStack_pop(stArrayStack *parrStack)
{
	int data = 0;

	if(arrayStack_is_empty(parrStack))
	{
		return -1;
	}
    data = parrStack->array[parrStack->pos];
	parrStack->pos--;

	return data;
}
/*入棧*/
int arrayStack_push(stArrayStack *parrStack,int data)
{
	if(arrayStack_is_full(parrStack))
	{
		return -1;
	}

    parrStack->pos++;
	parrStack->array[parrStack->pos] = data;

	return 0;
}

int arrayStack_push_new(stArrayStack*parrStack,int data)
{
	int *ptmp = NULL;

	/*如果棧不滿,直接插入*/
	if(!arrayStack_is_full(parrStack))
	{
		return arrayStack_push(parrStack,data);
	}

	/*如果棧已經滿,申請記憶體*/
    ptmp = (int *)malloc(2*parrStack->size*sizeof(int));
	if (ptmp == NULL)
	{
		return -1;
	}

	memcpy(ptmp,parrStack->array,parrStack->size*sizeof(int));

	free(parrStack->array);

    parrStack->array = ptmp;
	parrStack->size = 2*parrStack->size;
	parrStack->pos++;
    parrStack->array[parrStack->pos] = data;

	return ;
}

void arrayStack_dump(stArrayStack *parrStack)
{
	int i = 0;

	if (arrayStack_is_empty(parrStack))
	{
		printf("\r\n arrayStack is empty.");
		return;
	}
	printf("\r\narrayStack size = %d,pos= %d,",
			parrStack->size,parrStack->pos);
	for(i = 0; i <= parrStack->pos; i++)
	{
		printf("\r\narry[%d] = %d",i,parrStack->array[i]);
	}
}

int main()
{
	int i = 0;
	int ret = 0;
	stArrayStack * parrStack = NULL;

	printf("\r\n create size = 4 arrayStack.");

	parrStack = arrayStack_create(4);
	if (parrStack == NULL)
	{
	    printf("\r\n create size = 4 arrayStack faided.");
		return 0;
	}

	for (i = 0; i < 5; i++)
	{
		ret = arrayStack_push(parrStack,i);
		if(ret != 0)
		{
	        printf("\r\n push size = %d arrayStack faided.",i);

		}
	}
	arrayStack_dump(parrStack);
		
	ret = arrayStack_push_new(parrStack,4);
	if(ret != 0)
	{
	        printf("\r\n push size = %d arrayStack faided.",4);
    }
	arrayStack_dump(parrStack);

	arrayStack_destory(parrStack);
    
	return;
}

2、鏈式棧的實現

棧的應用 1.棧在函式呼叫中的應用 作業系統給每個執行緒分配了一塊獨立的記憶體空間,這塊記憶體被組織成“棧”這種結構,用來儲存函式呼叫時的臨時變數。每進入一個函式,就會將其中的臨時變數作為棧幀入棧,當被呼叫函式執行完成,返回之後,將這個函式對應的棧幀出棧。 2.棧在表示式求值中的應用(比如:34+13*9+44-12/3) 利用兩個棧,其中一個用來儲存運算元,另一個用來儲存運算子。我們從左向右遍歷表示式,當遇到數字,我們就直接壓入運算元棧;當遇到運算子,就與運算子棧的棧頂元素進行比較,若比運算子棧頂元素優先順序高,就將當前運算子壓入棧,若比運算子棧頂元素的優先順序低或者相同,從運算子棧中取出棧頂運算子,從運算元棧頂取出2個運算元,然後進行計算,把計算完的結果壓入運算元棧,繼續比較。 3.棧在括號匹配中的應用(比如:{}{

()}) 用棧儲存為匹配的左括號,從左到右一次掃描字串,當掃描到左括號時,則將其壓入棧中;當掃描到右括號時,從棧頂取出一個左括號,如果能匹配上,則繼續掃描剩下的字串。如果掃描過程中,遇到不能配對的右括號,或者棧中沒有資料,則說明為非法格式。 當所有的括號都掃描完成之後,如果棧為空,則說明字串為合法格式;否則,說明未匹配的左括號為非法格式。 4.如何實現瀏覽器的前進後退功能? 我們使用兩個棧X和Y,我們把首次瀏覽的頁面依次壓如棧X,當點選後退按鈕時,再依次從棧X中出棧,並將出棧的資料一次放入Y棧。當點選前進按鈕時,我們依次從棧Y中取出資料,放入棧X中。當棧X中沒有資料時,說明沒有頁面可以繼續後退瀏覽了。當Y棧沒有資料,那就說明沒有頁面可以點選前進瀏覽了。 思考:

  1. 我們在講棧的應用時,講到用函式呼叫棧來儲存臨時變數,為什麼函式呼叫要用“棧”來儲存臨時變數呢?用其他資料結構不行嗎? 答:**因為函式呼叫的執行順序符合後進者先出,先進者後出的特點。**比如函式中的區域性變數的生命週期的長短是先定義的生命週期長,後定義的生命週期短;還有函式中呼叫函式也是這樣,先開始執行的函式只有等到內部呼叫的其他函式執行完畢,該函式才能執行結束。 正是由於函式呼叫的這些特點,根據資料結構是特定應用場景的抽象的原則,我們優先考慮棧結構。 2.我們都知道,JVM 記憶體管理中有個“堆疊”的概念。棧記憶體用來儲存區域性變數和方法呼叫,堆記憶體用來儲存 Java 中的物件。那 JVM 裡面的“棧”跟我們這裡說的“棧”是不是一回事呢?如果不是,那它為什麼又叫作“棧”呢? 答:JVM裡面的棧和我們這裡說的是一回事,被稱為方法棧。和前面函式呼叫的作用是一致的,用來儲存方法中的區域性變數。