C語言實現(摘自資料結構與演算法分析 C語言描述)
阿新 • • 發佈:2019-01-05
一、概述:
棧(stack)是限制插入和刪除只能在一個位置上進行的表,該位置是表的末端,叫做棧的頂(top)。對棧的基本操作有Push(進棧)和Pop(出棧),前者相當於插入,後者則是刪除最後插入的元素。
棧有時又叫做LIFO(後進先出)表。在圖1中描述的模型只象徵著Push是輸入操作而Pop和Top是輸出操作。
圖1 棧模型:通過Push向棧輸入,通過Pop從棧輸出
二、實現
1. 棧的連結串列實現
檔名:stack_list.h
檔名:stack_list.c#ifndef _STACK_LIST_H #define _STACK_LIST_H #define ElementType int struct Node; typedef struct Node *PtrToNode; typedef PtrToNode Stack; int IsEmpty( Stack S ); Stack CreateStack( void ); void DisposeStack( Stack S ); void MakeEmpty( Stack S ); void Push( ElementType X, Stack S ); ElementType Top( Stack S ); void Pop( Stack S ); #endif /* _STACK_LIST_H */
檔名:main.c#include "stack_list.h" #include "fatal.h" struct Node { ElementType Element; PtrToNode Next; }; int IsEmpty( Stack S ) { return S->Next == NULL; } Stack CreateStack( void ) { Stack S; S = malloc( sizeof( struct Node ) ); if( S == NULL ) FatalError( "Out of space!!!" ); S->Next = NULL; MakeEmpty( S ); return S; } void MakeEmpty( Stack S ) { if( S == NULL ) Error( "Must use CreateStack first" ); else while( !IsEmpty( S ) ) Pop( S ); } void Push( ElementType X, Stack S ) { PtrToNode TmpCell; TmpCell = malloc( sizeof( struct Node ) ); if( TmpCell == NULL ) FatalError( "Out of space!!!" ); else { TmpCell->Element = X; TmpCell->Next = S->Next; S->Next = TmpCell; } } ElementType Top( Stack S ) { if( !IsEmpty( S ) ) return S->Next->Element; Error( "Empty stack" ); return 0; } void Pop(Stack S ) { PtrToNode FirstCell; if( IsEmpty( S ) ) Error( "Empty Stack" ); else { FirstCell = S->Next; S->Next = S->Next->Next; free( FirstCell ); } }
#include <stdio.h> #include "stack_list.h" int main() { Stack S; int n, num, m; int i; S = CreateStack(); printf( "Initialization complete.\n" ); printf( "Please input the number of elements in the stack:\n" ); scanf( "%d", &n ); printf( "Please input %d elements push into stack:\n", n ); for(i = 0; i < n; i++ ) { scanf( "%d", &num ); Push( num, S ); } printf( "Please input the numbers you want pop out from the stack(no more than:%d)\n", n ); scanf( "%d", &n ); printf( "Pop out from the stack %d elements in turns:\n", n ); for( i = 0; i < n; i++ ) { m = Top( S ); Pop( S ); printf( "%3d",m ); } printf( "\n" ); return 0; }
2. 棧的陣列實現
檔名:stack_array.h
#ifndef _STACK_ARRARY_H
#define _STACK_ARRARY_H
struct StackRecord;
typedef struct StackRecord *Stack;
#define ElementType int
int IsEmpty( Stack S );
int IsFull( Stack S );
Stack CreateStack( int MaxElements );
void DisposeStack( Stack S );
void MakeEmpty( Stack S );
void Push( ElementType X, Stack S );
ElementType Top( Stack S );
void Pop( Stack S );
ElementType TopAndPop( Stack S );
#endif /* _STACK_ARRARY_H */
檔名:stack_array.c
#include "stack_array.h"
#include "fatal.h"
#define EmptyTOS ( -1 )
#define MinStackSize ( 5 )
struct StackRecord
{
int Capacity;
int TopOfStack;
ElementType *Array;
};
Stack
CreateStack( int MaxElements )
{
Stack S;
if( MaxElements < MinStackSize )
Error( "Stack size is too small" );
S = malloc( sizeof( struct StackRecord ) );
if( S == NULL )
FatalError( "Out of space!!!" );
S->Array = malloc( sizeof( ElementType ) * MaxElements );
if( S->Array == NULL )
FatalError( "Out of space!!!" );
S->Capacity = MaxElements;
MakeEmpty( S );
return S;
}
void
DisposeStack( Stack S )
{
if( S != NULL )
{
free( S-> Array );
free( S );
}
}
int
IsEmpty( Stack S )
{
return S->TopOfStack == EmptyTOS;
}
void
MakeEmpty( Stack S )
{
S->TopOfStack = EmptyTOS;
}
void
Push( ElementType X, Stack S )
{
if( IsFull( S ) )
Error( "Full Stack" );
else
S->Array[ ++S->TopOfStack ] = X;
}
int
IsFull( Stack S )
{
return S->TopOfStack == S->Capacity - 1;
}
ElementType
Top( Stack S )
{
if( !IsEmpty( S ) )
return S->Array[ S->TopOfStack ];
Error( "Empty Stack" );
return 0; /* Return value used to avoid
* warning */
}
void
Pop( Stack S )
{
if( IsEmpty( S ) )
Error( "Empty Stack" );
else
S->TopOfStack--;
}
ElementType
TopAndPop( Stack S )
{
if( !IsEmpty( S ) )
return S->Array[ S->TopOfStack-- ];
Error( "Empty Stack" );
return 0; /* Return value used to avoid
* warning */
}
檔名:main.c
#include <stdio.h>
#include "stack_array.h"
#include "fatal.h"
int main()
{
Stack S;
int n, num, m;
int i;
S = CreateStack( 10 );
printf( "Initialization complete.\n" );
printf( "Please input the number of elements in the stack:\n" );
scanf( "%d", &n );
printf( "Please input %d elements push into stack:\n", n );
for( i = 0; i < n; i++ )
{
scanf( "%d", &num );
Push( num, S );
}
printf( "Top of the stack:%d\n", Top( S ) );
printf( "Please input the numbers you want pop out from the stack(no more than %d):\n", n );
scanf( "%d", &n );
printf( "Pop out from the stack %d elements in turns:\n", n );
for( i = 0; i < n; i++ )
{
m = TopAndPop( S );
printf( "%3d", m );
}
printf( "\n" );
return 0;
}
附錄:上述程式碼中用到了Error、FatalError等函式,其實現如下(即fatal.h檔案):
#include <stdio.h>
#include <stdlib.h>
#define Error( Str ) FatalError( Str )
#define FatalError( Str ) fprintf( stderr, "%s\n", Str ), exit( 1 )
三、應用
1. 平衡符號:
編譯器檢查你的程式的語法錯誤,但是常常由於缺少一個符號(如遺漏一個花括號或是註釋起始符)引起編譯器列出上百行的診斷,而真正的錯誤並沒有找出。 在這種情況下,一個有用的工具就是檢驗是否每件事情都能成對出現的一個程式。於是,每一個右花括號、右方括號及右圓括號必然對應其相應的左括號。序列“[()]”是合法的,但“[(])”是錯誤的。顯然,不值得為此編寫一個大型程式,事實上檢驗這些事情是很容易的。為簡單起見,我們就圓括號、方括號和花括號進行檢驗並忽略出現的任何其他字元。 這個簡單的演算法用到一個棧,敘述如下: 做一個空棧。讀入字元直到檔案尾。如果字元是一個開放符號,則將其推入棧中。如果字元是一個封閉符號,則當棧空時報錯。否則,將棧元素彈出。如果彈出的符號不是對應的開放符號,則報錯。在檔案尾,如果棧非空則報錯。 演算法實現:bool
balance( char ch, Stack S )
{
switch( ch ) {
case '(':
case '[':
case '{':
Push( ch, S );
break;
case ')':
if( IsEmpty( S ) || Top( S ) != '(' )
{
return false;
}
Pop( S );
break;
case ']':
if( IsEmpty(S) || Top(S) != '[' )
{
return false;
}
Pop( S );
break;
case '}':
if( IsEmpty( S ) || Top( S ) != '{' )
{
return false;
}
Pop( S );
break;
default:
break;
}
return true;
}
2. 字尾表示式
3. 中綴到字尾的轉換
4. 函式呼叫
附錄:上述程式碼中用到了Error、FatalError等函式,其實現如下(即fatal.h檔案):
#include <stdio.h>
#include <stdlib.h>
#define Error( Str ) FatalError( Str )
#define FatalError( Str ) fprintf( stderr, "%s\n", Str ), exit( 1 )
備註:本文摘自《資料結構與演算法分析 C語言描述 Mark Allen Weiss著》,程式碼經gcc編譯測試通過。
附件下載: