栈
栈的定义:
限定仅在表尾进行插入和删除操作的线性操作
栈的基本实现(顺序与链式)
//--------------------------------顺序存储结构1-----------------------------------------------------
typedef struct
{
ElemType data[MAXSIZE];
int top;
}SqStack;
//栈的基本操作
//1.顺序存储结构
void InitStack(SqStack &s){
//初始化一个空栈
s.top = -1;
}//InitStack
void StackEmpty(SqStack s){
//判断是否为空
if(s.top == -1)
return 1;
return 0;
}//StackEmpty
void Push(SqStack &s,ElemType e){
//数据e进栈
if(s.top == MAXSIZE)
return 0;
s.data[++s.top] = e;
}//Push
void Pop(SqStack s,ElemType &e){
//利用数据e出栈
if(StackEmpty(s))
return 0;
e = s.data[s.top--];
}
//-------------------------------顺序存储结构2-----------------------------------------------------
#define STACK_INIT_SIZE 100//存储空间的分配量
#define STACKINCREMENT 10//
typedef struct
{
int *base;
int *top;
int stacksize;
}SqStack;
void InitStack(SqStack &s){
//初始化一个空栈
s.base = (int *)malloc(STACK_INIT_SIZE * sizeof(int));
if(!s.base){
printf("申请地址失败!\n");
exit(0);
}
s.top = s.base;
s.stacksize = STACK_INIT_SIZE;
}//InitStack
int StackEmpty(SqStack s){
//判断栈栈是否为空
return s.top == s.base ? 1:0;
}//StackEmpty
void Push(SqStack &s,int e){
//进栈操作
if(s.top - s.base >=STACK_INIT_SIZE){
S.base = (int *)realloc(s.base,(s.stacksize + STACKINCREMENT)*sizeof(int));
if(!s.base){
printf("增加空间失败!");
exit(0);
}
*(s.top++) = e;
s.stacksize = STACK_INIT_SIZE + STACKINCREMENT;
}
}//Push
void Pop(SqStack &s,int &e){
//出栈操作
if(!StackEmpty(s))
{
printf("此时栈为空!\n");
exit(0);
}
e = *(--s.top);
}//Pop
void GetTop(SqStack &s,int &e){
//取栈顶元素
if(!StackEmpty(s)){
printf("此时栈为空!\n");
exit(0);
}
s.top -= 1;
e = *(s.top);
}//GetTop
//郁闷 pop 与 GetTop函数有什么不同!
//为什么顺1的Pop函数有问题????????????????????????????
//顺序存储结构1与顺序存储结构2的区别:
// 顺序存储结构1: 当栈为空时,top指针指向“下标-1”,Push操作时top先自加,之后赋值。Pop操作时先赋值,再top自减
// 顺序存储结构2: 当栈为空时,top指针指向首基址,Push操作时先赋值再top自加,Pop操作时先自减再赋值。相当于栈空
//时top指向”下标0“
//------------------------------------链式存储结构--------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct StackNode
{
ElemType data;
struct StackNode *next;
}StackNode,*LinkStackPtr;
typedef struct LinkStack
{
LinkStackPtr top;//栈指针
int count;//记录结点的个数
}LinkStack;
void InitStack(LinkStack &s){
//初始化空栈
s.top = (LinkStackPtr)malloc(sizeof(StackNode));
if(!s.top){
printf("初始化失败!\n");
exit(0);
}
s.top->next = NULL;
}//InitStack
int StackEmpty(LinkStack s){
//判断栈是否为空!
LinkStackPtr p;
p = s.top;
if(!p){
return 1;
}
return 0;
}//StackEmpty
void Push(LinkStack &s,ElemType e){
//进栈操作
LinkStackPtr p = (LinkStackPtr)malloc(sizeof(StackNode));
if(!p){
printf("申请结点失败!\n");
exit(0);
}
p->data = e;
p->next = s.top;//相当于top指针加加
s.top = p;//赋值
s.count ++;
}//Push
int Pop(LinkStack &s,ElemType &e){
//出栈操作
LinkStackPtr p;
if(StackEmpty(s)){//一般c,c++ 判断StackEmpty(s)可以是int,返回类型1,0;但是在java中需要用boolean类型!
printf("此时栈空!\n");
//exit(0);
return -1;
}
e = s.top->data;
p = s.top;
s.top = p->next;
free(p);
s.count--;
return 0;
}//Pop
栈的特例(栈的共享)
//-------------------------------------------栈的共享---------------------------------------------
//栈共享实现原理:用数组,定义top1,top2分别位于数组的起始位置,然后向中间靠拢
//栈空的条件:top1=-1,top2=n;
//栈满的条件:top1+1=top2;
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
typedef int SElemType;
typedef struct
{
SElemType data[MAXSIZE];
int top1;//头指针
int top2;//尾指针
}SqDoubleStack;
void InitStack(SqDoubleStack &s){
//初始化空栈
s.top1 = -1;
s.top2 = MAXSIZE;
}//InitStack
void Push(SqDoubleStack &s,SElemType e,int top){
//在栈s中第top个位置插入数据e
if(s.top1 + 1 == s.top2){
printf("栈满,插入失败!\n");
exit(0);
}
if(top == 1){
s.top1++;
s.data[s.top1] = e;
}
else if(top == 2){
s.top2--;
s.data[s.top2] = e;
}
else{
printf("top输入错误!1 or 2\n");
}
}//Push
int StackEmpty(SqDoubleStack s){
//判断栈是否为空!
if(s.top1 == (-1) && s.top2 == MAXSIZE){
return 1;
}
return 0;
}//StackEmpty
void Pop(SqDoubleStack &s,SElemType &e,int top){
//在栈s中将top位置的数据出栈,用e带出
if(StackEmpty(s)){
printf("此时栈空!\n");
exit(0);
}
if(top == 1){
e = s.data[s.top1--];
}
else if(top == 2){
e = s.data[s.top2++];
}
else{
printf("top输入错误!1 or 2\n");
}
}//Pop
引入递归与迭代(简单说明)
递归:把一个直接调用自己或通过一系列的调用语句间接地调用自己的函数。
递归使用的是选择结构,递归能使程序的结构更清晰,更简洁,更容易读,但是大量的递归调用会创建函数的副本,会耗费大量的时间和内存。迭代则不需要反复调用函数和占用额外的内存。
队列队列的基本定义
只允许在一端进行插入操作,而在另一端进行删除操作的线性表
一般队列容易造成假溢出现象,引入循环队列
队列的实现就是定义两个指针,front(指向队头)rear(指向队尾),
队空的条件front==rear,假设定义一个数组,长度为5,将五个数字入队列,入队过程中,rear++,front不变。再做出队操作,假设前三个数据出队,front++ 指向下标3,rear不变。若再进行入队列,此时出现溢出现象,而此时数组并没有满。
循换队列解决假溢出的两种方法
1.设置flag=0,rear == front 此时为空。Flag =1,rear==front 此时为满。
2.留出一个位置。由循环队列,队满的条件为: (rear+1)%QueueSize == front;
循环队列的基本实现:
//-------------------------------------队列基本操作-----------------------------------------------
//队列的顺序存储结构,链式存储结构
//-------------------------------------队列的顺序存储结构-----------------------------------------
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
typedef int QElemType;
typedef struct
{
QElemType data[MAXSIZE];
int front;//头指针
int rear;//尾指针,如果队列不空,指向队列元素的下一个位置;留出一个空位置,方便判断队空与满
}SqQueue;
void InitQueue(SqQueue &q){
//初始化一个队列
q.front = 0;
q.rear = 0;
}//InitQueue
void EnQueue(SqQueue &q,QElemType e){
//数据进队
if((q.rear + 1)%MAXSIZE == q.front){
printf("此时队满,进队失败!\n");
exit(0);
}
q.data[q.rear] = e;
q.rear = (q.rear + 1)%MAXSIZE;
}//EnQueue
int QueueEmpty(SqQueue q){
//判断队是否为空!
if(q.rear == q.front){
return 1;
}
return 0;
}//QueueEmpty
void DeQueue(SqQueue &q,QElemType &e){
//数据出队
if(QueueEmpty(q)){
printf("此时队列已空!\n");
exit(0);
}
e = q.data[q.front];
q.front = (q.front + 1) % MAXSIZE;
}//DeQueue
//-----------------------------------------队列的链式存储结构--------------------------------------
#include <stdio.h>
#include <stdlib.h>
typedef int QElemType;
typedef struct QNode
{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct
{
QueuePtr front,rear;
}LinkQueue;
void InitQueue(LinkQueue &q){
//初始化一个空队
q.front= q.rear= (QueuePtr)malloc(sizeof(QNode));
if(!q.front){
printf("初始化空队失败!\n");
exit(0);
}
//q.front = q.rear;
q.front->next = NULL;
}//InitQueue
void EnQueue(LinkQueue &q,QElemType e){
//数据入队操作
QueuePtr s = (QueuePtr)malloc(sizeof(QNode));
if(!s){
printf("申请结点失败!\n");
exit(0);
}
s->data = e;
s->next = NULL;
q.rear->next = s;
q.rear = s;
}//EnQueue
int QueueEmpty(LinkQueue q){
//判断队是否为空
if(q.front == q.rear)
return 1;
return 0;
}//QueueEmpty
void DeQueue(LinkQueue &q,QElemType &e){
//数据出队列
QueuePtr p;
if(QueueEmpty(q)){
printf("此时队列已空!\n");
exit(0);
}
p = q.front->next;
e = p->data;
q.front->next = p->next;
if(q.rear == p){
q.rear = q.front;
}
free(p);
}//DeQueue