数据结构-栈和队列(逆波兰表达式,中缀表达式,进制转换,中缀表达式转换为后缀表达式,队列的链式和顺序存储)
栈和队列
栈
栈的顺序存储结构1(非数组方法)
/*
栈
栈的顺序存储结构(非数组方法实现)
*/
# include<stdio.h>
# include<stdlib.h>
# define STACK_INIT_SIZE 100
# define STACK_ADD_SIZE 50
typedef struct Sqstack
{
int *base;
int *top;
int Stack_size; // 记录栈的当前可用的容量
}Sqstack;
typedef Sqstack *P_Sqstack; // p_Sqstack 称为指向Sqstack 栈的一个指针的声明,可以当做栈名
// 栈的初始化
void stack_init(P_Sqstack s)
{
s->base = (int *)malloc(STACK_INIT_SIZE * sizeof(int));
if( !s->base ) exit(1); // 内存分配失败,退出
s->top = s->base;
s->Stack_size = STACK_INIT_SIZE;
}
// 入栈操作
void stack_push(P_Sqstack s, int e)
{
if(s->top - s->base >= s->Stack_size)// 栈顶-栈底 如果大于可用容量,则说明栈满了
{
// 栈空间不够,为栈重新分配空间
s->base = (int *)realloc(s->base,(s->Stack_size + STACK_ADD_SIZE) * sizeof(int));
if( !s->base ) exit(1); // 内存不够分配,退出
s->top = s->base + s->Stack_size; // 由于新申请了一块内存,所以就要重新设置栈顶。(需要特别注意这里是 原栈底地址加上栈的原size,指针与int型相加减表示地址上向前或后移动了(同指针所指数据的类型为单位)几个单位)
s->Stack_size = s->Stack_size + STACK_ADD_SIZE;
}
*(s->top) = e;
s->top ++;
}
// 出栈操作
int stack_pop(P_Sqstack s)
{
if(s->top == s->base)
{
printf("错误:栈为空!\n");
return -1;
}
s->top --;
int e = *(s->top);
printf("%d已出栈\n",e);
return e;
}
// 栈打印
void stack_printf(P_Sqstack s)
{
int *p = s->top;
printf("栈:\n----------\n");
while(p != s->base)
{
p --;
printf("%d\n",*p);
}
printf("----------\n");
}
// 清空一个栈
void stack_clear(P_Sqstack s)
{
s->top = s->base;
}
// 销毁一个栈
void stack_destory(P_Sqstack s)
{
int len = s->Stack_size;
while(len --)
{
free(s->base);
s->base ++;
}
s->base = NULL;
s->top = NULL;
s->Stack_size = 0;
}
int main()
{
P_Sqstack stack_1 = (P_Sqstack)malloc(sizeof(Sqstack));
stack_init(stack_1);
stack_printf(stack_1);
int opcnt;
printf("入栈操作:请输入操作次数?\n");
scanf("%d",&opcnt);
while(opcnt --)
{
int e;
printf("请输入入栈元素的值?\n");
scanf("%d",&e);
stack_push(stack_1,e);
stack_printf(stack_1);
}
printf("出栈操作:请输入操作次数?\n");
scanf("%d",&opcnt);
while(opcnt --)
{
stack_pop(stack_1);
stack_printf(stack_1);
}
printf("清空栈:\n");
stack_clear(stack_1);
stack_printf(stack_1);
stack_destory(stack_1);
system("pause");
return 0;
}
栈实现二进制到十进制的转换
/*
利用栈实现二进制转换成十进制
转换公式如下
(XnXn-1Xn-2...X3X2X1)2 = X1*2^0 + X2*2^1+...+Xn*2^(n-1)
比如输入100 输出4
0*2^0 + 0*2^1 + 1*2^2 = 4
*/
# include<stdio.h>
# include<stdlib.h>
# include<math.h>
# define STACK_MAX_SIZE 100
# define STACK_ADD_SIZE 10
typedef struct P_stack
{
int *top;
int *base;
int stack_size;
int length;
}P_stack;
typedef P_stack *stack;
void stack_init(stack s)
{
s->base = (int *)malloc(STACK_MAX_SIZE * sizeof(int));
if( ! s->base) exit(1);
s->top = s->base;
s->stack_size = STACK_MAX_SIZE;
s->length = 0;
}
void stack_push(stack s, int e)
{
if(s->top - s->base >= s->stack_size)
{
s->base = (int *)realloc(s->base , (s->stack_size + STACK_ADD_SIZE)*sizeof(int));
if(! s->base) exit(1);
s->length ++;
s->top = s->base + s->stack_size;
s->stack_size = STACK_ADD_SIZE + s->stack_size;
}
*(s->top ++) = e;
s->length ++;
}
int stack_printf(stack s)
{
if(s->top == s->base)
{
printf("栈为空!\n");
return 0;
}
int *p = s->top;
p --;
printf("-------------\n");
while(p != s->base)
{
printf("| %d |\n",*p);
p --;
}
printf("| %d |\n",*p);
printf("-------------\n");
return 1;
}
int stack_pop(stack s)
{
if(s->top == s->base)
{
int e = *(s->top);
s->length --;
printf("已经为空栈\n");
return e ;//空栈返回-1
}
s->top -- ;
int e = *(s->top);
s->length --;
return e;
}
int main()
{
stack stacka = (stack)malloc(sizeof(P_stack));
stack_init(stacka);
printf("请输入一个二进制数:\n");
char ch;
while((ch = getchar()) != '\n')
{
int i = ch - 48 ;
stack_push(stacka,i);
}
stack_printf(stacka);
printf("栈长度为:%d\n",stacka->length);
printf("开始计算:\n");
int stacklength = stacka->length;
int res = 0;
for(int i = 0 ; i < stacklength ; i ++)
{
int e = stack_pop(stacka);
res += e * pow(2,i);
}
stack_printf(stacka);
printf("该二进制数转化为十进制数的结果为:%d\n",res);
system("pause");
return 0;
}
栈实现逆波兰计算器(十以内加减乘整除)
/*
逆波兰计算器(十以内加减乘除(整除),只可以输入逆波兰表达式)
逆波兰表达式,又称为后缀表达式
例:正常的表达式为 (1+2)*(3-4) 转化为逆波兰表达式就是 1 2 + 3 4 - *
例:正常的表达式为 a+(b-c)*d 转化为逆波兰表达式就是 a b c - d * +
字符0-9的ASCII码值是48-57
记录:scanf函数遇到空格或者换行符就会停止读入,gets函数可以读取整行的字符串直到换行符
*/
# include<stdio.h>
# include<stdlib.h>
# include<math.h>
# define STACK_MAX_SIZE 101
# define STACK_ADD_STACK 10
# define OK 1
# define ERROR 0
// 定义栈的结构体
typedef struct Stack_struct
{
int *base;
int *top;
int Stack_size;
int Stack_length;
}Stack_struct;
typedef Stack_struct *pstack;
// 栈的初始化
void stack_init(pstack stack1)
{
stack1->base = (int*)malloc(STACK_MAX_SIZE * sizeof(int));
if(! stack1->base) exit(1);
stack1->top = stack1->base;
stack1->Stack_length = 0;
stack1->Stack_size = STACK_MAX_SIZE;
}
// 栈的push
void stack_push(pstack stack1,int e)
{
if(stack1->top - stack1->base >= stack1->Stack_size)
{
stack1->base = (int *)realloc(stack1->base,(STACK_MAX_SIZE + STACK_ADD_STACK) * sizeof(int));
stack1->top = stack1->base + stack1->Stack_size;
stack1->Stack_size += STACK_ADD_STACK;
}
*(stack1->top ++) = e;
stack1->Stack_length ++;
}
// 返回出栈的栈顶元素
int stack_pop(pstack stack1)
{
if(stack1->top == stack1->base)
{
printf("栈为空!\n");
exit(0);
}
int e = *(--stack1->top);
stack1->Stack_length --;
return e;
}
// 打印栈
void stack_printf(pstack stack1)
{
int *topp = stack1->top;
printf("打印栈:\n");
printf("-------------------\n");
while(topp != stack1->base)
{
printf("| %d |\n",*(-- topp));
}
printf("-------------------\n");
}
int caculate(int op,int n1,int n2,int *n)
{
switch (op)
{
case '+': *n = n1 + n2; break;
case '-': *n = n1 - n2; break;
case '*': *n = n1 * n2; break;
case '/': *n = n1 / n2; break;
default: return ERROR;
}
return OK;
}
int main()
{
pstack stacka = (pstack)malloc(sizeof(Stack_struct));
stack_init(stacka);
// 注意小数也得能输入进去,所以就不能使用while getchar了
char expression[1000],ch = 'a'; // expression是用来储存表达式的字符数组,ch这里随表初始化一个,不为\0 和\n就行
int idx = 0; // 用来表示字符数组的下标
printf("请输入表达式(逆波兰表达式)!\n");
scanf("%s",expression);
int n = 0;
while(expression[idx] != '\0')
{
// printf("%c",expression[idx ++]);
if(expression[idx] >= 48 && expression[idx] <= 57)
{
int e = expression[idx] - 48;
stack_push(stacka,e);
}
else if(expression[idx] < 48 || expression[idx] > 57)
{
int n2 = stack_pop(stacka);
int n1 = stack_pop(stacka);
caculate(expression[idx],n1,n2,&n);
stack_push(stacka,n);
printf("计算过程:%d和%d的计算结果是%d\n",n1,n2,n);
}
idx ++;
}
printf("最后结果为%d\n",n);
// printf("%s\n",expression);
system("pause");
return 0;
}
中缀表达式转换为后缀表达式,在使用逆波兰计算器输出
比如:1+(2-3)*4+10/5
转化为后缀表达式的过程:
将所有的符号入栈,数字直接输出
1输出 |输出 : 1
+入符号栈 |符号栈:+
(入符号栈 |符号栈:+(
2输出 |输出 : 1 2
-入符号栈 |符号栈:+(-
3输出 |输出 : 1 2 3
)出现,符号栈开始pop操作直到下一个pop出(符号,输出|1 2 3 -
*入符号栈 |符号栈: + *
4输出 |输出 : 1 2 3 - 4
下一个入栈的符号是+,优先级小于栈顶元素的优先级,所以* pop
*出栈 |输出 : 1 2 3 - 4 *
+入符号栈 |符号栈: + +
10输出 |输出 : 1 2 3 - 4 10
/入符号栈 |符号栈: + + /
5输出 |输出 : 1 2 3 - 4 * 10 5
符号栈开始pop:所以输出就是 1 2 3 - 4 * 10 5 / + +
然后就是逆波兰计算了......
/*
计算器
输入计算式输出结果
例如:
输入: 1 + ( 2 - 3 ) * 4 + 10 / 5 =
输出:-1
中缀表达式转化为后缀表达式,对后缀表达式计算输出结果
注意:可以小数输入,十位数百百位数等都要支持。
*/
# include<stdlib.h>
# include<stdio.h>
const int EXPRESSMAXLENGTH = 1010; // 表达式最大长度
const int STACKMAXSIZE = 100010; // 栈的最大容量
char stack[STACKMAXSIZE],epr[EXPRESSMAXLENGTH]; // 栈和后缀表达式字符串
int top,cnt; // cnt 用来记下后缀字符串数组用到了哪里
void stack_push(char e)
{
if(top == STACKMAXSIZE - 1)
{
printf("栈已满!\n");
exit(1);
}
stack[top ++] = e;
}
char stack_pop(void)
{
if(top == 0)
{
printf("栈为空\n");
exit(1);
}
char e = stack[--top];
return e;
}
void stack_clear(void)
{
top = 0;
}
void stack_sign_in(char e)
{
if(e == ')')
{
top --;
while(stack[top] != '(')
{
epr[cnt ++] = stack[top --];
}
}
else
{
top --;
while(stack[top] == '*' || stack[top] == '/' )
{
// if(stack[top] == '(') break;
epr[cnt ++] = stack[top --];
}
// 减号优先级比加号大一点点
while(e == '+' && stack[top] == '-') epr[cnt ++] = stack[top --];
top ++;
stack_push(e);
}
}
int main()
{
char e;
printf("请输入中缀表达式:\n");
// 中缀表达式转化为后缀表达式存入字符串数组epr
while((e = getchar()) != '\n')
{
if(e >= '0' && e <= '9') epr[cnt ++] = e;
else
{
switch(e)
{
case '+':stack_sign_in(e); break;
case '-':stack_sign_in(e); break;
case ')':stack_sign_in(e); break;
case '*':stack_push(e); break;
case '/':stack_push(e);break;
case '(':stack_push(e);break;
default:exit(1); break;
}
}
}
while(top != 0) epr[cnt ++] = stack[-- top];
printf("中缀表达式转化为后缀表达式之后为:");
for(int i = 0 ; i <= cnt - 1 ; i ++) printf("%c",epr[i]);
printf("\n");
// 计算逆波兰表达式
for(int i = 0 ; i <= cnt - 1; i ++)
{
// 遇到数字就入栈,遇到运算符就弹栈,弹出两个将结果继续入栈
if(epr[i] >= '0' && epr[i] <= '9')
{
stack_push(epr[i]);
}
else
{
int n2 = stack_pop() - '0';
int n1 = stack_pop() - '0';
int n3;
switch(epr[i])
{
case '+': n3 = n1 + n2 ; break;
case '-': n3 = n1 - n2 ; break;
case '*': n3 = n1 * n2 ; break;
case '/': n3 = n1 / n2 ; break;
}
char n3_ = n3 + '0';
printf("计算过程:%d与%d的运算结果是%d\n",n1,n2,n3);
stack_push(n3_);
}
}
int res = stack_pop() - '0';
printf("最后的运算结果是%d\n",res);
system("pause");
return 0;
}
队列
链式存储实现
/*
队列 ----链式
实现:队列的初始化,入队列,出队列
*/
# include<stdio.h>
# include<stdlib.h>
# define OK 1
# define ERROR 0
typedef char elemtype;
typedef struct Node
{
elemtype data;
Node* next;
}Node;
typedef Node* pnode;
typedef struct Linkqueue
{
pnode rear; // 队尾指针
pnode front; // 队头指针
}Linkqueue;
typedef Linkqueue* pLinkqueue;
// 队列初始化
/*创建个头结点,让队头队尾指针指向这个头结点就可以了*/
pLinkqueue Queue_init(pLinkqueue plinkqueue)
{
pnode headnode = (pnode)malloc(sizeof(Node));
if( !headnode ) exit(0);
headnode->next = NULL;
plinkqueue->front = headnode;
plinkqueue ->rear = headnode;
return plinkqueue;
}
// 队列入队操作
/* 新申请一个结点,将结点从队尾插入 */
pLinkqueue Queue_en(pLinkqueue plinkqueue,elemtype e)
{
pnode pnewnode = (pnode)malloc(sizeof(Node));
if( !pnewnode ) exit(0);
pnewnode->next = NULL;
pnewnode->data = e;
plinkqueue->rear->next = pnewnode; // 将新结点接在队尾后面
plinkqueue->rear = pnewnode; // 新结点成为新的队尾
return plinkqueue;
}
// 队列出队操作
/* 将队头结点绕过,将队头结点的data保存到e中,free */
/* 这里需要讨论两种特殊情内框:队列只有一个元素-将front和rear指向头结点;队列空-直接返回或退出等 */
pLinkqueue Queue_de(pLinkqueue plinkqueue,elemtype* e)
{
if(plinkqueue->front == plinkqueue->rear)
{
printf("队列为空!\n");
exit(0);
}
pnode q = plinkqueue->front->next; // 队列front指向的是头结点,而头结点的下一个才是队列的第一个元素
plinkqueue->front->next = q->next;
*e = q->data;
// 如果出队后只有一个元素了就还需要去修改一下队尾指针rear
if(plinkqueue->rear == q) plinkqueue->rear = plinkqueue->front;
free(q);
return plinkqueue;
}
// 队列打印
/* front->next开始遍历直到rear结束 */
int Queue_printf(pLinkqueue plinkqueue)
{
if(plinkqueue->front == plinkqueue->rear)
{
printf("队列为空!!!\n");
return OK;
}
pnode q = plinkqueue->front->next;
printf("队列为:");
while(q != plinkqueue->rear)
{
printf("%c-",q->data);
q = q->next;
}
printf("%c\n",q->data);
return OK;
}
int main()
{
int op;
pLinkqueue queue = (pLinkqueue)malloc(sizeof(Linkqueue));
queue = Queue_init(queue);
printf("请输入入队操作个数:\n");
scanf("%d",&op);
printf("请输入要入队的元素:\n");
char e;
int i = 1;
while(op --)
{
getchar();
scanf("%c",&e);
Queue_en(queue,e);
printf("入队:执行%d次\n",i);
i ++;
}
Queue_printf(queue);
printf("请输入出队操作数:");
scanf("%d",&op);
while( op -- )
{
Queue_de(queue,&e);
printf("出队:出队元素为%c",e);
Queue_printf(queue);
}
system("pause");
return 0;
}
顺序存储实现
/*
数组/顺序表实现队列
如何利用数组前部分空闲的内存:让rear指针:rear = (rear + 1)%Arr_size (ps:当然前提是队列未满)
队列初始化
队列入队操作
队列出队操作
队列打印
*/
# include<stdio.h>
# include<stdlib.h>
typedef char elemtype;
// 初始化
const int MAX_SIZE = 10010;
elemtype queue[MAX_SIZE];
int rear,front;
// 入队操作
void queue_en(elemtype e)
{
if((rear + 1) % MAX_SIZE == front) exit(0); // 如果插入之后rear指针指向的位置和front指向的指针相等就说明了队列已满
queue[rear ++] = e;
}
// 出队操作
elemtype queue_de(void)
{
if(front == rear)
{
printf("队列为空!\n");
exit(0);
}
elemtype e = queue[front];
front = (front + 1) % MAX_SIZE;
return e;
}
// 队列打印
void queue_printf(void)
{
printf("队列为:\n");
for(int i = front; i != rear ; i = (i + 1) % MAX_SIZE )
{
printf("%c-",queue[i]);
}
}
int main()
{
int n;
elemtype e;
printf("请输入入队元素的个数\n");
scanf("%d",&n);
printf("请输入入队的元素\n");
while(n --)
{
getchar();
scanf("%c",&e);
queue_en(e);
}
queue_printf();
printf("请输入出队的个数:");
scanf("%d",&n);
while(n --)
{
e = queue_de();
printf("%c已出队\n",e);
}
queue_printf();
system("pause");
return 0;
}
rds_blogs