队列 - C语言实现(摘自数据结构与算法分析 C语言描述)

一、概述:

像栈一样,队列(queue)也是表。然而,使用队列时插入在一端进行而删除在另一端进行。

队列的基本操作是Enqueue(入队),它是在表的末端(叫做队尾(rear)插入一个元素,还有Dequeue(出队),它是删除(或返回)在表的开头(叫做队头(front)的元素。如图1所示显示一个队列的抽象模型。


图1 队列模型

二、实现

如同栈的情形一样,对于队列而言任何表的实现都是合法的。像栈一样,对于每一种操作,链表实现和数组实现都给出快速的 O(1)运行时间。

1. 队列的链表实现

文件名:queue_list.h
#ifndef _QUEUE_LIST_H
#define _QUEUE_LIST_H

#define ElementType int
struct Node;
struct QNode;
typedef struct Node *PtrToNode;
typedef PtrToNode Queue;


int IsEmpty( Queue Q );
Queue CreateQueue( void );
void DisposeQueue( Queue Q );
void MakeEmpty( Queue Q );
void Enqueue( ElementType X, Queue Q );
ElementType Front( Queue Q );
void Dequeue( Queue Q );
ElementType FrontAndDequeue( Queue Q );

#endif /* _QUEUE_LIST_H */
文件名:queue_list.c
#include "queue_list.h"
#include "fatal.h"

typedef struct QNode
{
  ElementType Element;
  struct QNode *Next;
}QNode, *QNodePtr;

struct Node {
  QNodePtr Front;
  QNodePtr Rear;
};

int
IsEmpty( Queue Q )
{
  return Q->Front == Q->Rear;
}

Queue
CreateQueue( void )
{
  Queue Q;
  Q = malloc( sizeof( struct Node ) );
  Q->Front = Q->Rear = malloc( sizeof( struct QNode ) );
  if (!Q->Front)
    FatalError( "Out of space!!!");
  Q->Front->Next = NULL;
  return Q;
}

void
MakeEmpty( Queue Q )
{
  if( Q == NULL )
    Error( "Must use CreateQueue first" );
  else
    while( !IsEmpty( Q ) )
      Dequeue( Q );
}

void
DisposeQueue( Queue Q )
{
  while( Q->Front ) {
    Q->Rear = Q->Front->Next;
    free( Q->Front );
    Q->Front = Q->Rear;
  }
  printf( "\nDispose queue completed!!!" );
}
void
Enqueue( ElementType X, Queue Q )
{
  QNodePtr p;
  p = malloc( sizeof( QNode ) );
  if (!p)
    FatalError( "Out of space!!!" );
  p->Element = X;
  p->Next = NULL;
  Q->Rear->Next = p;
  Q->Rear = p;
}

ElementType
Front( Queue Q )
{
  if ( !IsEmpty( Q ) )
    return Q->Front->Next->Element;
  return 0; /* Return value used to avoid warning */
}

void
Dequeue( Queue Q )
{
  if ( !IsEmpty( Q ) )
  {
    QNodePtr p;
    p = malloc( sizeof( QNode ) );
    if (!p)
      FatalError( "Out of space!!!" );
    p = Q->Front->Next;
    Q->Front->Next = p->Next;
    if ( Q->Rear == p )
      Q->Rear = Q->Front;
    free( p );
  }
}

ElementType
FrontAndDequeue( Queue Q )
{
  if ( !IsEmpty( Q ) )
  {
    QNodePtr p;
    p = malloc( sizeof( QNode ) );
    if (!p)
      FatalError( "Out of space!!!" );
    p = Q->Front->Next;
    ElementType temp = 0;
    temp = p->Element;
    Q->Front->Next = p->Next;
    if ( Q->Rear == p )
      Q->Rear = Q->Front;
    free( p );
    return temp;
  }
  Error( "Empty queue!!!" );
  return 0; /* Return value used to avoid warning */
}
文件名:queue_list_main.c
#include <stdio.h>
#include "queue_list.h"

int main()
{
  int n, num, m;
  int i;
  Queue Q = CreateQueue();
  printf( "Initialization complete.\n" );
  if ( IsEmpty( Q ) )
    printf( "Queue is empty \n" );
  printf( "Please input the number of elements in the queue:" );
  scanf( "%d", &n );
  printf( "Please input %d elements put in queue:", n );
  for(i = 0; i < n; i++ )
  {
    scanf( "%d", &num );
    Enqueue( num, Q );
  }
  printf( "Front element: %d.\n", Front( Q ) );
  printf( "Elements in queue:" );
  while ( !IsEmpty( Q )) {
    printf( "%3d", FrontAndDequeue( Q ) );
  }
  DisposeQueue( Q );
  printf( "\n" );
  return 0;
}

2. 队列的数组实现

文件名:queue_array.h
#ifndef QUEUE_ARRAY_H
#define QUEUE_ARRAY_H

#define ElementType int
struct QueueRecord;
typedef struct QueueRecord *Queue;

int IsEmpty( Queue Q );
int IsFull( Queue Q );
Queue CreateQueue( int MaxElements );
void DisposeQueue( Queue Q );
void MakeEmpty( Queue Q );
void Enqueue( ElementType X, Queue Q );
ElementType Front( Queue Q );
void Dequeue( Queue Q );
ElementType FrontAndDequeue( Queue Q );

#endif /* QUEUE_ARRAY_H */
文件名:queue_array.c
#include "queue_array.h"
#include "fatal.h"

/* Place in implementation file
 * Queue implementation is a dynamically allocated array*/
#define MinQueueSize ( 5 )

struct QueueRecord
{
  int Capacity;
  int Front;
  int Rear;
  int Size;
  ElementType *Array;
};

int
IsEmpty( Queue Q )
{
  return Q->Size == 0;
}

void
MakeEmpty( Queue Q )
{
  Q->Size = 0;
  Q->Front = 1;
  Q->Rear = 0;
}

static int
Succ( int value, Queue Q )
{
  if ( ++value == Q->Capacity )
    value = 0;
  return value;
}

void
Enqueue( ElementType X, Queue Q )
{
  if( IsFull( Q ) )
    Error( "Full queue" );
  else
  {
    Q->Size++;
    Q->Rear = Succ( Q->Rear, Q );
    Q->Array[ Q-> Rear ] = X;
  }
}

void
Dequeue( Queue Q )
{
  if ( IsEmpty( Q ) )
    Error( "Empty queue" );
  else
  {
    Q->Size--;
    Q->Front++;
  }
}

ElementType
FrontAndDequeue( Queue Q )
{
  ElementType temp = 0;
  if ( IsEmpty( Q ) )
    Error( "Empty queue" );
  else
  {
    Q->Size--;
    temp= Q->Array[ Q->Front ];
    Q->Front = Succ( Q->Front, Q );
  }
  return temp;
}

ElementType
Front( Queue Q )
{
  if ( !IsEmpty( Q ) )
    return Q->Array[ Q->Front ];
  Error( "Empty queue" );
  return 0;  /* Return value used to avoid warning */
}

int
IsFull( Queue Q )
{
  return Q->Size == Q->Capacity;
}

Queue
CreateQueue(int MaxElements )
{
  Queue Q;

  if ( MaxElements < MinQueueSize )
    Error( "Queue size is too small!!!" );
  Q = malloc( sizeof( struct QueueRecord ) );
  if ( Q == NULL )
    FatalError( "Out of space!!!" );
  Q->Array = malloc( sizeof( ElementType ) * MaxElements );
  if ( Q->Array == NULL )
    FatalError( "Out of Space!!!" );
  Q->Capacity = MaxElements;
  MakeEmpty( Q );

  return Q;
}

void
DisposeQueue( Queue Q )
{
  if ( Q != NULL )
  {
    free( Q->Array );
    free( Q );
  }
}
文件名:queue_main.c
#include <stdio.h>
#include "queue_array.h"

int
main()
{
  int size;
  printf( "Please input queue size: " );
  scanf( "%d", &size );
  Queue Q = CreateQueue( size );
  ElementType temp;
  printf( "Please input queue elements(seperate by space): " );
  while ( !IsFull( Q ) )
  {
    scanf( "%d", &temp );
    Enqueue( temp, Q );
  }

  printf( "Dequeue queue in turn: " );
  while ( !IsEmpty( Q ) )
  {
    printf( "%3d", FrontAndDequeue( Q ) );
  }
  printf( "\n" );
  DisposeQueue( Q );
  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 )

备注:本文摘自《数据结构与算法分析 C语言描述 Mark Allen Weiss著》,代码经gcc编译测试通过。

附件下载:http://download.csdn.net/detail/shuxiao9058/4212437#queue-array.tar.gz,http://download.csdn.net/detail/shuxiao9058/4212435#queue-list.tar.gz

#include #include #include //队列最大长度 #define MAX_QUEUE 1024 //偷懒,就用静态队列了 static int mQueue[MAX_QUEUE]; //队列插入 void InsertData(int **Front, int **Rear) { if (*Rear + 1 == *Front && (*Rear + 1 - MAX_QUEUE != *Front)) { //当队列数据已满,返回 puts("Queue Size Overflow!\n"); return; } else if (*Rear - mQueue > MAX_QUEUE) { //实现的是类似循环队列,但由于是静态线性队列(数组) //而不是用链表来实现的,所以到静态队列(数组)尾部,尾指针自动指向(数组)头部 *Rear = mQueue; } puts("Input Data:"); scanf("%d", *Rear); //输入数据后,尾指针后移 *Rear += 1; } //从头指针删除一个队列中的数据 void DeleteData(int **Front, int **Rear) { if (*Front == *Rear) { //头指针尾指针重合,队列空,不能删除,返回 puts("Queue Empty!\n"); return; } else if (*Front - mQueue > MAX_QUEUE) { //参考 Rear *Front = mQueue; } //从头指针删除一个数据 *Front += 1; } //显示队列数据 void ShowData(int **Front, int **Rear) { int *temp; for (temp=*Front; temp!=*Rear; temp++) { printf("%d --> ", *temp); } puts("\n"); } void usage(void) { puts("1. Insert Data"); puts("2. Delete Data"); puts("3. Show Data"); } int main(int argc, char **argv) { //头指针,尾指针 //队列的一个特性 First in first out FIFO int *pFront, *pRear; int op_code; //初始化队列,头指针和尾指针此时指向的地址相同 pFront = pRear = mQueue; while (1) { usage(); scanf("%d", &op_code); switch (op_code) { case 1: printf("%p\n", pFront); printf("%d\n", *pFront); InsertData(&pFront, &pRear); break; case 2: DeleteData(&pFront, &pRear); break; case 3: ShowData(&pFront, &pRear); break; default: break; } } return 0; }
### C语言中栈和队列实现应用 #### 栈的实现 栈是一种后进先出(LIFO, Last In First Out)的数据结构,在C语言中可以通过数组或链表来实现。以下是基于动态数组的栈实现: ```c #include <stdio.h> #include <stdlib.h> #define MAX 4 typedef struct { int* _a; int _top; int _capacity; } Stack; // 初始化栈 void StackInit(Stack* ps) { ps->_a = (int*)malloc(sizeof(int) * MAX); if (!ps->_a) { perror("StackInit::malloc"); exit(1); } ps->_top = -1; // 初始状态为空,因此_top设为-1 [^4] ps->_capacity = MAX; } // 入栈操作 void StackPush(Stack* ps, int data) { if (ps->_top == ps->_capacity - 1) { // 如果栈满,则扩容 int newcap = ps->_capacity * 2; int* tmp = (int*)realloc(ps->_a, sizeof(int) * newcap); if (!tmp) { perror("realloc fail"); exit(1); } ps->_a = tmp; ps->_capacity = newcap; } ps->_a[++ps->_top] = data; // 将新元素压入栈顶 [^4] } ``` 上述代码展示了如何初始化一个栈以及向其中添加元素。 --- #### 队列实现 队列是一种先进先出(FIFO, First In First Out)的数据结构,同样可以使用数组或链表实现。以下是基于循环数组的队列实现: ```c #include <assert.h> typedef struct { int* val; size_t head; size_t tail; size_t capacity; } Queue; // 初始化队列 void QueueInit(Queue* pmp) { pmp->val = (int*)malloc(sizeof(int) * 4); // 动态分配内存存储队列元素 [^3] if (!pmp->val) { perror("QueueInit::malloc"); return; } pmp->head = 0; // 头部索引初始为0 pmp->tail = 0; // 尾部索引初始为0 pmp->capacity = 4; // 初始容量为4 } ``` 以上代码实现队列的基本初始化过程。 --- #### 应用场景分析 1. **栈的应用** - 表达式求值:利用栈处理括号匹配、计算四则运算等问题[^1]。 - 函数调用管理:操作系统使用栈保存函数调用记录及局部变量信息。 - 迷宫问题中的回溯算法:通过栈记录路径并尝试寻找解法[^2]。 2. **队列的应用** - 任务调度:计算机系统常用队列安排进程执行顺序。 - 广度优先搜索(BFS):借助队列逐层遍历图或树结构节点。 - 缓冲区管理:打印机缓冲区按请求时间先后打印文档。 --- #### 综合示例——表达式求值 以下是一个简单的表达式求值程序框架,展示栈的实际用途: ```c #include <ctype.h> double EvaluateExpression(const char* expr) { double result = 0; Stack num_stack, op_stack; StackInit(&num_stack); StackInit(&op_stack); while (*expr != '\0') { if (isdigit(*expr)) { StackPush(&num_stack, atoi(expr)); // 数字入数栈 } else if (strchr("+-*/", *expr)) { StackPush(&op_stack, *expr); // 符号入操作符栈 } expr++; } // 计算逻辑省略... return result; } ``` 此代码片段仅提供思路,具体细节需进一步完善。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值