下面写的代码可能感觉会很乱,所以加上了目录,意在为了引导,也就是你需要回顾哪个算法,就能够快速定位到该位置,如果从上往下去找的话,估计脑壳也疼死了。
二、栈和队列的存储结构
(一)栈的顺序存储结构
- 结构体的声明
#define MAX_SIZE 30 //设置顺序表最大容量
typedef struct
{
int data[MAXSIZE]; //存放栈中的元素,MAXSIZE为最大结点个数
int top; //top,栈顶指针
}SQ_STACK;
- 栈的初始化
/*
method:
初始化一个栈
param:
sq_stack 栈
*/
void Init_Stack(SQ_STACK* sq_stack)
{
sq_stack->top = -1; //栈内元素为空,栈顶指针设置为-1
}
- 判断栈是否为空
/*
method:
判断栈是否为空
param:
sq_stack 栈
*/
int Is_Stack_Empty(SQ_STACK* sq_stack)
{
if (sq_stack->top == -1) //栈顶指针为-1,即为空
return OK;
else
return ERROR;
}
- 进栈操作
/*
method:
进栈操作
param:
sq_stack 栈
data 要进栈的元素值
*/
int Push(SQ_STACK* sq_stack, int data)
{
if (sq_stack->top == MAXSIZE - 1) //判断是否栈满
return ERROR;
sq_stack->data[++sq_stack->top] = data; //入栈,++sq_stack->top 这里 先将sq_stack->top自增,然后再存储
return OK;
}
- 出栈操作
/*
method:
出栈操作
param:
sq_stack 栈
data 出栈的元素值
*/
int Pop(SQ_STACK* sq_stack,int *data)
{
if (sq_stack->top == -1) //判断是否栈空
return ERROR;
(*data) = sq_stack->data[sq_stack->top--]; //sq_stack->top-- 这里先取出来值,然后sq_stack->top再自减
return OK;
}
(二)栈的链式存储结构
- 结构体的声明
typedef struct LSTACK
{
int data; //数据与
struct LSTACK* next; //指针域
}LSTACK;
- 栈的初始化
/*
method:
初始化一个栈
param:
lstack 栈
*/
void Init_LStack(LSTACK *lstack)
{
lstack->next = NULL; //将指针置位NULL
}
- 判断栈是否为空
/*
method:
判断栈是否为空
param:
lstack 栈
*/
int Is_LStack_Empty(LSTACK* lstack)
{
if (lstack->next == NULL) //判断是否栈空
return OK;
else
return ERROR;
}
- 进栈操作
/*
method:
进栈操作
param:
lstack 栈
data 要进栈的元素值
*/
int L_Push(LSTACK* lstack, int data)
{
LSTACK* q;
q = (LSTACK*)__vcrt_malloc_normal(sizeof(LSTACK)); //为新结点创建内存空间
q->data = data; //新创建的结点存储数据
q->next = lstack->next; //入栈操作
lstack->next = q;
return OK;
}
- 出栈操作
/*
method:
出栈操作
param:
lstack 栈
data 出栈的元素值
*/
int L_Pop(LSTACK* lstack, int* data)
{
LSTACK* p;
if (lstack->next == NULL) //判断是否栈空
return ERROR;
p = lstack->next; //出栈操作
*data = p->data;
lstack->next = p->next;
__vcrt_free_normal(p); //释放内存
return OK;
}
(三)队列的顺序存储结构
- 双链表结构体
#define MAXSIZE 20
typedef struct
{
int data[MAXSIZE]; //存放到队列中的元素,MAXSIZE为最大结点个数
int front; //队头指针
int rear; //队尾指针
}SQ_QUEUE;
- 队列的初始化
/*
method:
初始化一个队列
param:
sq_queue 队
*/
void Init_Queue(SQ_QUEUE* sq_queue)
{
sq_queue->front = sq_queue->rear = 0; //队列内元素为空,队列首尾指针相同,设置为0
}
- 判断队列是否为空
/*
method:
判断队列是否为空
param:
sq_queue 队
*/
int Is_Queue_Empty(SQ_QUEUE* sq_queue)
{
if (sq_queue->front == sq_queue->rear) //队头指针指向队尾指针即为空
return OK;
else
return ERROR;
}
- 进队操作
/*
method:
进队操作
param:
sq_queue 队
data 要进队的元素值
*/
int En_Queue(SQ_QUEUE* sq_queue, int data)
{
if ((sq_queue->rear + 1)%MAXSIZE == sq_queue->front) //判断是否队列已满
return ERROR;
sq_queue->rear = (sq_queue->rear + 1) % MAXSIZE; //为了循环插入到队列中
sq_queue->data[sq_queue->rear] = data; //入队
return OK;
}
- 出队操作
/*
method:
出队操作
param:
sq_queue 栈
data 出队的元素值
*/
int De_Queue(SQ_QUEUE* sq_queue, int* data)
{
if (sq_queue->front == sq_queue->rear) //判断是否队列为空
return ERROR;
sq_queue->front = (sq_queue->front + 1) % MAXSIZE; //为了构成循环队列
*data = sq_queue->data[sq_queue->front]; //出队
return OK;
}
(四)队列的链式存储结构
- 结构体的声明
typedef struct LNODE //链式队列的结点的结构体
{
int data; //用于存放数据元素
struct LNODE* next; //指向下一个结点
}LNODE;
typedef struct LQUEUE //队头队尾结构体
{
LNODE* front; //队头指针
LNODE* rear; //队尾指针
}LQUEUE;
- 队列的初始化
/*
method:
初始化一个队列
param:
sq_queue 队
*/
void Init_LQueue(LQUEUE* lqueue)
{
lqueue->front = lqueue->rear = NULL; //队列内元素为空,队列首尾指针相同,设置为0
}
- 判断队列是否为空
/*
method:
判断队列是否为空
param:
lqueue 队
*/
int Is_LQueue_Empty(LQUEUE* lqueue)
{
if (lqueue->front == NULL || lqueue->rear == NULL) //判断是否队列为空
return OK;
else
return ERROR;
}
- 进队操作
/*
method:
进队操作
param:
lqueue 队
data 要进队的元素值
*/
int En_LQueue(LQUEUE* lqueue, int data)
{
LNODE* p = (LNODE*)__vcrt_malloc_normal(sizeof(LNODE)); //分配内存
p->data = data; //获取进队元素
p->next = NULL;
if (lqueue->front == NULL || lqueue->rear == NULL) //判断是否队列为空
{
lqueue->front = lqueue->rear = p; //第一个元素,队头队尾都指向该结点
}
else
{
lqueue->rear->next= p; //入队操作
lqueue->rear = p;
}
return OK;
}
- 出队操作
/*
method:
出队操作
param:
lqueue 栈
data 出队的元素值
*/
int De_LQueue(LQUEUE* lqueue, int* data)
{
LNODE* p;
if (lqueue->front == NULL || lqueue->rear == NULL) //判断是否队列为空,队空不能出队
return ERROR;
else if (lqueue->front == lqueue->rear) //只有一个结点
{
p = lqueue->front; //出队操作
lqueue->front = lqueue->rear = NULL; //队头队尾设置为空
}
else //如果有多个结点
{
p = lqueue->front; //出队操作
lqueue->front = lqueue->front->next; //队头向后移动
}
*data = p->data; //获取出队列的值
__vcrt_free_normal(p); //释放内存
return OK;
}
(五)栈的应用
-
顺序栈的应用----括号匹配
/* method: 匹配括号 param: exp 存放表达式的数组。例如char exp[] = "((a+b)*c)/d"; n为12 n 检查表达式的字节数目 */ int match(char exp[], int n) { char stack[MAXSIZE]; //定义栈 int top = -1; //定义栈头位置 for (int i = 0; i < n; i++) { if (exp[i] == '(') //如果为 ( ,进栈 { stack[++top] = '('; } else if (exp[i] == ')') //如果为 ) 出栈 { if (top == (-1)) //如果栈为空 return ERROR; else --top; //出栈 } } if (top == -1) //如果最后栈为空,则匹配 return OK; else return ERROR; //栈非空,不匹配 }
-
链式栈的应用----后缀式的运算
/* method: 根据操作符进行运算 param: a 数据a operate 操作符 b 数据b */ int OP(int a, char operate, int b) { //判断操作符进行相关操作 if (operate == '+') return a + b; else if (operate == '-') return a - b; else if (operate == '*') return a * b; else if (operate == '/') { if (b != 0) return a / b; else { printf("分母为0,错误!\n"); return ERROR; } } } /* method: 计算后缀式 param: exp 存放后缀式的数组 */ int Compute(char exp[]) { int stack[MAXSIZE]; //定义栈 int top = -1; //定义栈头位置 char op; //用于接收运算符 char num1, num2, num3; //取出栈中的值 for (int i = 0; exp[i] != '\0'; i++) { if ((exp[i]-'0') >= 0 && (exp[i]-'0') <= 9) { stack[++top] = exp[i] - '0'; //字符与整形之间转化 } else { op = exp[i]; //获得运算符 num1 = stack[top--]; //取出最后一个值 num2 = stack[top--]; //取出倒数第二个值 num3 = OP(num2, op, num1); //计算出num3 stack[++top] = num3; //将num3入栈 } } return stack[top]; //返回最终的数值 }
-
队列的应用
-
队列在计算机系统的应用
-
解决主机和外部设备之间速度不匹配问题
仅以主机和打印机之间速度不匹配为例。主机输出速度较快,打印机速度较慢,因此需要将打印的数据存放到打印缓冲区,打印机按照先进先出的顺序依次取出要打印的数据,打印完再去发送请求。
-
解决多用户引起的资源竞争问题
在一个带有多终端的系统中,有多个用户需要根据CPU各自运行程序,它们向操作系统提出占用CPU的请求,操作系统将这些请求按照先后顺序存放到队列中,每次把CPU分给队首请求的用户,运行一段时间后,令其出队,依次进行。
-
-
(六)特殊矩阵的压缩存储
-
对称矩阵
/* method: 对称矩阵的压缩存储----下三角 param: matrices 要压缩存储的二维矩阵 row 矩阵的行数 colomn 矩阵的列数 str 压缩存储的数组 */ /* 公式:如果为下三角, 下标从(0,0)开始, k = ( i*(i+1) / 2 + j ) i >= j k = ( j*(j+1) / 2 + i ) i < j 如果从(1,1)开始 k = ( i*(i-1) / 2 + j-1 ) i >= j k = ( j*(j-1) / 2 + i-1 ) i <= j */ /*对称矩阵例子 int Symmetry[3][3] = { {1, 2, 3}, {2, 4, 5}, {3, 5, 8} }; */ void Sym_Mat(int matrices[][3],int row,int colomn,int str[]) { int i_row = 0, i_col = 0; int num = 0; for (i_row; i_row < row; ++i_row) { i_col = 0; for (i_col; i_col < colomn; ++i_col) { if (i_row >= i_col) num = i_row * (i_row + 1) / 2 + i_col ; else num = i_col * (i_col + 1) / 2 + i_row ; str[num] = matrices[i_row][i_col]; } } }
-
下三角矩阵
/* method: 对称矩阵的压缩存储----下三角矩阵 param: matrices 要压缩存储的二维矩阵 row 矩阵的行数 colomn 矩阵的列数 str 压缩存储的数组 */ /* 公式同对称矩阵相同,唯一的区别就是将其他的相同元素存放到了数组的最后位置 */ /*下三角矩阵例子 int Triangular[3][3] = { {1, 1, 1}, {2, 4, 1}, {3, 5, 8} }; */ void Tri_Mat(int matrices[][3], int row, int colomn, int str[]) { int i_row = 0, i_col = 0; int num = 0; for (i_row; i_row < row; ++i_row) //遍历每一行 { i_col = 0; for (i_col; i_col < colomn; ++i_col) //遍历每一列 { if (i_row >= i_col) num = i_row * (i_row + 1) / 2 + i_col; //计算存储位置 //else //num = i_col * (i_col + 1) / 2 + i_row; //这里不存储 str[num] = matrices[i_row][i_col]; //按照公式存放到对应数组的位置 } } str[num + 1] = matrices[0][colomn - 1]; //将下三角矩阵的上方元素C存放到最后一个元素 }
-
三对角矩阵
/* method: 对称矩阵的压缩存储----三对角矩阵 param: matrices 要压缩存储的二维矩阵 row 矩阵的行数 colomn 矩阵的列数 str 压缩存储的数组 */ /* 公式 下标从(0,0)开始, k = 2i + j (| i-j | <= 1) 下标从(1,1)开始, k = 2(i-1) + j - 1 (| i-j | <= 1) */ /*三对角矩阵的例子 int Opposite[4][4] = { {1, 2, 1, 1}, {3, 4, 5, 1}, {1, 6, 7, 8}, {1, 1, 9, 10} }; */ void Opp_Mat(int matrices[][4], int row, int colomn, int str[]) { int i_row = 0, i_col = 0; int num = 0; for (i_row; i_row < row; ++i_row) //遍历每一行 { i_col = 0; for (i_col; i_col < colomn; ++i_col) //遍历每一列 { if (abs(i_row - i_col) <= 1) { num = 2 * i_row + i_col; //计算存储位置 str[num] = matrices[i_row][i_col]; //按照公式存放到对应数组的位置 } } } str[num + 1] = matrices[0][colomn - 1]; //将C给最后一个元素 }