wangc
Oct 23, 2016
栈与队列也属于线性表,但是某些操作受限而应用特殊情况的限定性的数据结构。
栈(STACK)
栈是限定仅在表尾进行插入或删除操作的线性表,栈的修改是按后进先出的原则进行的,因此,栈有称为后进先出(Last In First Out, LIFO)的线性表。
对栈来说,表尾段有其特殊含义,称为栈顶(top),相应的,表头段称为栈低(bottom)。
- ADT定义如下:
ADT Stack {
数据对象:D = { ai| ai∈ElemSet, i=1,2,...,n, n≥0 }
数据关系:Rl = { <a(i-1),ai> | a(i-1),ai∈D, i=2,...,n }
约定an端为栈顶,a1端为栈底。
基本操作:
InitStack( &S )
DestroyStack( &S )
ClearStack( &S )
StackEmpty( &L )
ListTraverse( S )
// 上面的基本操作和线性表要求一样
GetTop( S )
初始条件:栈S已存在且非空
操作结果:返回S的栈顶元素不修改栈顶指针
Push(&S, e)
初始条件:栈S已存在
操作结果:插入元素e为新的栈顶元素
Pop(&S, &e)
初始条件:栈S已存在且非空
操作结果:删除S的栈顶元素,并用e返回其值
} ADT Stack
队列(queue)
队列是一种先进先出(First In First Out)的线性表,他只允许在表的一端进行插入,而在另一端删除元素.
在队列中允许插入的一端称为队尾(rear),允许删除的一端称为队头(front)。
- ADT定义如下:
ADT Queue { 数据对象:D = { ai| ai∈ElemSet, i=1,2,...,n, n≥0 } 数据关系:Rl = { <a(i-1),ai> | a(i-1),ai∈D, i=2,...,n } 约定an端为队头,a1端为队尾。 基本操作: InitQueue( &Q) DestroyQueue( &Q ) ClearQueue( &Q ) QueueEmpty( &Q ) QueueLength( &Q ) QueueTraverse( Q ) // 上面的基本操作和线性表要求一样 GetHead( Q ) 初始条件:队列Q已存在且非空 操作结果:返回Q的队头元素 EnQueue(&Q, e) 初始条件:队列Q已存在 操作结果:插入元素e为新的队尾元素 DeQueue(&Q, &e) 初始条件:Q为非空队列 操作结果:删除Q的对头元素,并用e返回其值 } ADT Queue
顺序栈
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include "E:\小c的数据结构\0. 绪论\Status.h"
using std::cin;
using std::cout;
using std::endl;
#define MAXSIZE 100
#define FALSE 0
#define TRUE 1
#define SElemType int
typedef struct
{
SElemType *base; // 当top等于base时表示空栈
SElemType *top; // top指针用以指示栈顶元素在顺序栈中的位置
int stacksize;
}SqStack;
Status InitStack(SqStack &S)
{
S.base = new SElemType[MAXSIZE]; //依然用数组空间分配顺序结构
if(!S.base) exit(OVERFLOW); //如果base的值为NULL说明栈不存在
S.top = S.base;
S.stacksize = MAXSIZE;
cout << "链栈初始化成功!\n" ;
return OK;
}
// 入栈操作:在栈顶插入一个新的元素
Status Push(SqStack &S)
{
SElemType e;
cout << "输入要入栈的值:";
cin >> e;
if(S.top-S.base==S.stacksize) return ERROR;
*S.top++ = e;
/* 优先级:++,. , *, = 。所以解释为先S.top作为一个变量,
头*S.top = e 将元素压入栈顶,然后执行后置的++操作,头指针重置。*/
cout << "链栈初始化成功!\n" ;
return OK;
}
void ClearStack(SqStack &S)
{
S.top=S.base;
}
Status StackEmpty(SqStack S)
{
if(S.base - S.top) return FALSE;
else return TRUE;
}
void ListLength(SqStack S)
{
cout << "链栈有" << (S.top-S.base) << "个元素\n";
}
Status Pop(SqStack &S)
{
if(S.top==S.base) return ERROR;
--S.top;
cout << "元素已出栈\n";
}
Status GetTop(SqStack S, SElemType &e)
{
if(S.base==S.top) return ERROR;
e = *(S.top-1);
return OK;
}
Status Push_R(SqStack &S, int e)
{
if(S.top-S.base==S.stacksize) return ERROR;
*S.top++ = e;
/* 优先级:++,. , *, = 。所以解释为先S.top作为一个变量,
头*S.top = e 将元素压入栈顶,然后执行后置的++操作,头指针重置。*/
}
void CreateList( SqStack &S )
{
for( int i=0; i<5; ++i)
{
srand(i);
SElemType e = rand()%100+1;
Push_R(S, e);
}
cout << "5个随机栈元素创建成功。\n";
}
void OutputList(SqStack S)
{
cout << "数据:";
for(int *p = S.top; p!=S.base; --p)
cout << *(p-1) << " ";
cout << endl;
}
链栈
#ifndef SEQUENCELIST_H
#define SEQUENCELIST_H
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include "E:\小c的数据结构\0. 绪论\Status.h"
using std::cin;
using std::cout;
using std::endl;
typedef int SElemType;
/* 单链表结构体 */
typedef struct StackNode
{
SElemType data;
struct StackNode *next;
}StackNode;
typedef StackNode* LinkStack;
/* 初始化函数 */
Status InitList( LinkStack &S )
{
S = NULL; // 无需头结点
cout << "链栈初始化成功!\n" ;
return OK;
}
Status Push(LinkStack &S)
{
SElemType e;
cout << "输入要入栈的值:";
cin >> e;
StackNode *p = new StackNode;
p->data = e;
p->next = S;
S = p;
cout << "元素已入栈。\n";
return OK;
}
void Push_R(LinkStack &S, int e)
{
StackNode *p = new StackNode;
p->data = e;
p->next = S;
S = p;
}
Status Pop(LinkStack &S)
{
if(S==NULL) return ERROR;
StackNode *p = S;
S = S->next;
delete p;
cout << "元素已出栈\n";
return OK;
}
void GetTop(LinkStack S)
{
if(S != NULL)
cout << "栈顶元素为" << S->data << endl;
}
void CreateList( LinkStack &S )
{
for( int i=0; i<5; ++i)
{
StackNode *p;
srand(i);
SElemType e = rand()%100+1;
Push_R(S, e);
}
cout << "5个随机栈元素创建成功。\n";
}
void ListLength(LinkStack S)
{
LinkStack p;
int i;
if(S)
{
i = 0;
p = S;
while(p)
{
i++;
p = p->next;
}
}
cout << "链栈有" << i << "个元素\n";
}
void OutputList(LinkStack S)
{
int i = 0;
StackNode *p = S;
cout << "\n数据为:" ;
while(p)
{
i++;
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
#endif
栈与递归
递归的栈式内存管理
- 函数调用的原理
当有多个函数构成嵌套调用时,按照“后调用先返回”的原则,上述函数之间的信息传递的控制转移必须通过“栈”来实现,即系统将整个程序运行时所需要的数据安排在一个栈中,每当调用一个函数时,就为它在栈顶分配一个存储区,每当一个函数退出时,就释放他的存储区,当前正在运行的函数的数据区必在栈顶。
函数调用前,系统需要完成的四项任务
- 保存返回地址
- 给形参以及局部变量分配相应的存储空间
- 接受从实参传过来的值
- 将控制转移的被调用函数的入口(执行函数体) 从被调用函数返回调用函数之前,应该完成以下三项任务
- 保存被调函数的计算结果
- 释放分配给它的存储空间
- 依照被调函数保存的返回地址将控制转移到调用函数
- 例子
// 链表正序输出
void TraverseList_1(LinkList L)
{
if( L )
{
cout << L->data << " ";
TraverseList_1(L->next);
}
}
// 链表倒序输出
void TraverseList_2(LinkList L)
{
if( L )
{
TraverseList_2(L->next);
cout << L->data << " ";
}
}
顺序队列
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include "E:\小c的数据结构\0. 绪论\Status.h"
using std::cin;
using std::cout;
using std::endl;
#define MAXSIZE 100
#define QElemType int
typedef struct {
QElemType *base; // 存储空间的基地址
int front; // 头指针,若队列不空,指向队列头元素
int rear; // 尾指针,若队列不空指向队尾的下一个位置
}SqQueue;
Status InitQueue(SqQueue &Q)
{
Q.base = new QElemType[MAXSIZE];
if(!Q.base) return ERROR;
Q.front = Q.rear = 0;
cout << "顺序队列初始化成功!\n" ;
return OK;
}
Status EnQueue( SqQueue &Q )
{
QElemType e;
cout << "输入要入栈的值:";
cin >> e;
if((Q.rear+1)%MAXSIZE == Q.front)
return ERROR;
Q.base[Q.rear] = e; // 新元素插入队尾
Q.rear = (Q.rear+1) % MAXSIZE; // 队尾指针循环加 1
cout << "元素已进队。\n";
return OK;
}
Status EnQueue_R( SqQueue &Q, QElemType e )
{
if((Q.rear+1)%MAXSIZE == Q.front)
return ERROR;
Q.base[Q.rear] = e; // 新元素插入队尾
Q.rear = (Q.rear+1) % MAXSIZE; // 队尾指针加 1
return OK;
}
Status DeQueue(SqQueue &Q)
{
if(Q.front == Q.rear) return ERROR;
// e = Q.base[Q.front];
Q.front = (Q.front+1)%MAXSIZE;
cout << "元素已出队\n";
return OK;
}
QElemType GetHead(SqQueue Q)
{
if(Q.front != Q.rear)
return Q.base[Q.front];
}
void CreateList( SqQueue &Q )
{
for( int i=0; i<5; ++i)
{
srand(i);
QElemType e = rand()%100+1;
EnQueue_R(Q, e);
}
cout << "5个随机队列元素创建成功。\n";
}
void ListLength(SqQueue Q)
{
cout << "队列有" << (Q.rear-Q.front+MAXSIZE)%MAXSIZE << "个元素" << endl;
}
void OutputList(SqQueue Q)
{
int t = 0;
cout << "\n数据为:" ;
while(t < (Q.rear-Q.front+MAXSIZE)%MAXSIZE )
{
cout << Q.base[t] << " ";
t++;
}
cout << endl;
}
链式队列
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include "E:\小c的数据结构\0. 绪论\Status.h"
using std::cin;
using std::cout;
using std::endl;
#define QElemType int
// 队列的链式结构
typedef struct QNode
{
QElemType data;
struct QNode *next;
}QNode;
typedef QNode* QueuePtr;
typedef struct
{
QueuePtr front;
QueuePtr rear;
}LinkQueue;
Status InitQueue(LinkQueue &Q)
{
Q.front = Q.rear = new QNode; //生成新节点作为头结点,对头队尾指针指向此节点
Q.front->next = NULL; // 头结点指针域制空
cout << "链式队列初始化成功!\n" ;
return OK;
}
Status EnQueue(LinkQueue &Q )
{
QElemType e;
cout << "输入要入队的值:";
cin >> e;
QueuePtr p = new QNode;
p->data = e;
p->next = NULL; Q.rear->next = p;
Q.rear= p;
cout << "元素已进队。\n";
return OK;
}
Status EnQueue_R(LinkQueue &Q, QElemType e )
{
QueuePtr p = new QNode;
p->data = e;
p->next = NULL; Q.rear->next = p;
Q.rear= p;
return OK;
}
Status DeQueue(LinkQueue &Q)
{
if(Q.front==Q.rear) return ERROR;
QueuePtr p = Q.front->next;
// e = p->data;
Q.front->next = p->next;
if(Q.rear==p) Q.rear = Q.front; // 若是最后一个元素删去了,队尾指针会丢失,需要重新赋值。
delete p;
cout << "元素已出队\n";
return OK;
}
QElemType GetHead(LinkQueue Q)
{
if(Q.front!=Q.rear)
return Q.front->next->data;
}
void CreateList( LinkQueue &Q )
{
for( int i=0; i<5; ++i)
{
srand(i);
QElemType e = rand()%100+1;
EnQueue_R(Q, e);
}
cout << "5个随机队列元素创建成功。\n";
}
void ListLength(LinkQueue Q)
{
int count = 0;
QueuePtr p = Q.front;
while(p!=Q.rear)
{
count++;
p = p->next;
}
cout << "队列有" << count << "个元素" << endl;
}
void OutputList(LinkQueue Q)
{
cout << "\n数据为:" ;
QueuePtr p = Q.front;
while(p!=Q.rear)
{
p = p->next;
cout << p->data << " ";
}
cout << endl;
}