1. 程式人生 > >C語言實現(摘自資料結構與演算法分析 C語言描述)

C語言實現(摘自資料結構與演算法分析 C語言描述)

一、概述:

棧(stack)是限制插入和刪除只能在一個位置上進行的表,該位置是表的末端,叫做棧的頂(top)。對棧的基本操作有Push(進棧)和Pop(出棧),前者相當於插入,後者則是刪除最後插入的元素。

棧有時又叫做LIFO(後進先出)表。在圖1中描述的模型只象徵著Push是輸入操作而Pop和Top是輸出操作。


圖1 棧模型:通過Push向棧輸入,通過Pop從棧輸出

二、實現

1. 棧的連結串列實現

檔名:stack_list.h

#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 */
檔名:stack_list.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 );
  }
}
檔名:main.c
#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編譯測試通過。

附件下載: