栈和队列 栈 栈的顺序存储结构1(非数组方法) 栈实现二进制到十进制的转换 栈实现逆波兰计算器(十以内加减乘整除) 中缀表达式转换为后缀表达式,在使用逆波兰计算器输出 队列 链式存储实现 顺序存储实现

栈和队列

栈的顺序存储结构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