欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C语言强化学习第一天(栈与队列)

程序员文章站 2022-03-12 21:51:50
...

英文:
top:头部,顶部
capacity:容量,大小
stack:栈
init = initialization:初始化
full:满
empty:空
push:压入
pop:弹出
queue:队列

1.结构体的专项训练:
1.1.结构体数组

/*结构体数组*/
#include <stdio.h>
//求数组元素个数
#define ARRYA_SIZE(x) (sizeof(x)/sizeof(x[0]))
/*声明描述学生信息的结构体*/
typedef struct student {
    char name[30]; //姓名
    int age; //年龄
    int sex; //性别
}stu_t;
int main(void)
{
    /*1.定义两个学生信息的结构体变量*/
    //stu_t info[] = {{"关羽", 18, 1}, {"黄蓉", 16, 0}};
    stu_t info[] = {
        {
            .sex = 1,
            .age = 18,
            .name = "关羽"
        },
        {
            .sex = 0,
            .age = 16,
            .name = "黄蓉"
        }
    };
    for(int i = 0; i < ARRYA_SIZE(info); i++)
        printf("%s %d %d\n", info[i].name, info[i].age, info[i].sex);
    info[0].age++;
    info[1].age++;
    for(int i = 0; i < ARRYA_SIZE(info); i++)
        printf("%s %d %d\n", info[i].name, info[i].age, info[i].sex);
    return 0;
}

1.2.结构体和函数指针组合

/*结构体和函数指针*/
#include <stdio.h>
//此声明告诉gcc stu_t声明在下面,前面需要用到
typedef struct student stu_t;
//声明函数指针数据类型
typedef void (*pfunc_t)(stu_t *);
//声明结构体
typedef struct student {
    char name[30]; //姓名 
    int age; //年龄
    int sex; //性别
    pfunc_t pfunc1; //函数指针变量将来指向一个操作函数
    pfunc_t pfunc2; //函数指针变量将来指向一个操作函数
}stu_t;
//定义打印学生信息函数show和grow
void show(stu_t *pstu){
    printf("%s %d %d\n", pstu->name, pstu->age, pstu->sex);
}
void grow(stu_t *pstu) {
    pstu->age++;
}
int main(void)
{
    //定义结构体变量描述学生信息
    stu_t  student1 = {
        .name = "刘备",
        .age = 19,
        .sex = 1,
        .pfunc1 = show, //指向show函数
        .pfunc2 = grow //指向grow函数
    };
    //调用student1学生的操作函数show和grow
    student1.pfunc1(&student1);//执行pfunc1 show
    student1.pfunc2(&student1);//执行pfunc2 grow
    student1.pfunc1(&student1);//执行pfunc1 show
    return 0;
}


第二阶段课程内容:数据结构和算法
数据结构:栈,队列,单链表,双链表,二叉树
算法:2个查找算法,5个排序算法
1.基本概念
数据结构:描述计算机中数据之间的关系和存储方式

2.数据结构分类
a)逻辑结构:描述数据之间的关系
b)物理结构:描述数据的存放方式
c)运算结构:描述数据的运算过程,例如:+,-等

3.逻辑结构
a)集合结构:强调总体,不强调数据之间的关系
例如:CSD1911班级就是一个集合结构,同学之间无关系
2,3,5,7…统称为素数
b)线性结构:描述数据一对一的前后关系
例如:排队打饭,公交车排队
c)树形结构:描述数据的一对多的关系
例如:树,家谱
d)网状结构:数据的多对多的关系
例如:蜘蛛网,网球拍

4.物理结构
a)顺序存储结构
采用数组来存储数据
b)链式存储结构
采用链表:单链表和双链表

5.结论:数据结构重点掌握:栈,队列,单链表,双链表,有序二叉树

6.数据结构之栈(又称堆栈)
a)栈的基本特性
具有后进先出的特性(Last In First Out=LIFO)
或者
具有先进后出的特性(First In Last Out=FILO)
例如:放书和取书,鸡尾酒
栈的操作只能操作栈顶!
入栈又称压栈
出栈又称弹栈

b)栈的操作基本原理
C语言强化学习第一天(栈与队列)

/*栈演示代码*/
#include <stdio.h>
#include <stdlib.h> //为了用malloc函数
/*声明描述栈属性信息的结构体*/
typedef struct stack {
    int *arr; //数组的首地址
    int cap; //栈的容量大小
    int top; //栈顶
}stack_t;
/*定义栈相关的操作函数*/
//1.给栈分配内存,让arr指向分配的内存的首地址
//并且把栈初始化为空栈(没有数据)
void stack_init(stack_t *stack, int cap)
{
    //分配内存,让arr指向分配的内存
    stack->arr = (int *)malloc(cap * sizeof(int));
    stack->cap = cap; //指定栈容量
    stack->top = 0; //空栈
}
//2.释放内存并且恢复到初始化状态
void stack_deinit(stack_t *stack) 
{
    free(stack->arr);
    stack->cap = 0;
    stack->top = 0;
}
//3.判断是否满
int stack_full(stack_t *stack)
{
    //栈顶top大于等于容量cap,就是满
    return stack->top >= stack->cap; //满返回1,不满返回0
}
//4.判断是否空
int stack_empty(stack_t *stack)
{
    return !stack->top; //空(top=0)返回1,不空返回0 
}
//5.入栈(压栈),向分配的内存中保存数据
//data:就是要保存的数据
void stack_push(stack_t *stack, int data)
{
    stack->arr[stack->top++] = data;
}
//6.出栈(弹栈),从栈中取出数据
int stack_pop(stack_t *stack)
{
    return stack->arr[--stack->top];
}
//7.仅仅获取栈顶元素(最上面的一个数字)
int stack_top(stack_t *stack)
{
    return stack->arr[stack->top-1];
}
//8.获取栈中目前保存数据的个数
int stack_size(stack_t *stack)
{
    return stack->top;
}
//测试主函数
int main(int argc, char *argv[])
{
    //1.定义栈
    stack_t stack; 

    //2.初始化栈,给栈分配存储数据的内存空间并且指定容量
    stack_init(&stack, 10);

    //3.判断空和满
    int ret = 0;
    ret = stack_full(&stack);
    printf("%s\n", ret ? "满":"不满");
    ret = stack_empty(&stack);
    printf("%s\n", ret ? "空":"不空");
   
    //4.压栈
    int i = 250;
    while(!stack_full(&stack)) {
        stack_push(&stack, i++);
    }
    ret = stack_full(&stack);
    printf("%s\n", ret ? "满":"不满");
    printf("栈顶的值是%d\n", stack_top(&stack));
    printf("栈的大小是%d\n", stack_size(&stack));

    //5.出栈
    while(!stack_empty(&stack)) {
        printf("%d ", stack_pop(&stack));
    }
    printf("\n");
    ret = stack_empty(&stack);
    printf("%s\n", ret ? "空":"不空");
    
    //6.释放内存
    stack_deinit(&stack);
    return 0;
}

7.数据结构之队列
a)特性:先进先出(First In First Out=FIFO),取数从队列的开头取,存储从队列尾部存
第一个元素又称首元素,最后一个元素又称尾元素
b)linux系统三大队列:
消息队列:进程间通信的一种手段
工作队列:延后执行的一种手段
等待队列:随时随地让进程休眠并且让进程随时随地被唤醒
C语言强化学习第一天(栈与队列)

/*队列*/
#include <stdio.h>
#include <stdlib.h>
/*声明描述队列属性的结构体*/
typedef struct queue {
    int *arr; //首地址
    int cap; //容量
    int size; //有效数据的个数
    int front; //前端(出队)
    int rear; //后端(入队)
}queue_t;
//1.定义分配内存和初始化队列函数
void queue_init(queue_t *queue, int cap)
{
    queue->arr = (int *)malloc(cap * sizeof(queue->arr[0]));//分配内存
    queue->cap = cap; //容量
    queue->size = 0; //无数
    queue->front = 0; 
    queue->rear = 0;
}
//2.释放内存并且恢复到初始状态
void queue_deinit(queue_t *queue)
{
    free(queue->arr);
    queue->cap = 0; 
    queue->size = 0; //无数
    queue->front = 0; 
    queue->rear = 0;

}
//3.判断是否满
int queue_full(queue_t *queue)
{
    return queue->size >= queue->cap; //满返回1,不满返回0
}
//4.判断是否空
int queue_empty(queue_t *queue)
{
    return !queue->size; //空返回1,不空返回0
}
//5.入队
void queue_push(queue_t *queue, int data)
{
    if(queue->rear >= queue->cap)
        queue->rear = 0; //如果队列的前面有空位置,重新定位rear,
                         //让队列变成一个循环队列
    queue->arr[queue->rear++] = data;
    queue->size++;
}
//6.出队
int queue_pop(queue_t *queue)
{
    if(queue->front >= queue->cap)
        queue->front = 0; //取到队尾,然后前面还有数据,重新定位front
    queue->size--;
    return queue->arr[queue->front++];
}
//7.获取有效数据的个数
int queue_size(queue_t *queue)
{
    return queue->size;
}
//8.获取队首元素的值
//测试主函数

int main(void)
{
    //1.定义队列
    queue_t queue;

    //2.初始化队列
    queue_init(&queue, 4);
    //3.入队:10 20 30 40
    for(int i = 10; i <= 40; i += 10) {
        if(!queue_full(&queue)) {
            queue_push(&queue, i);
        } 
    }
    //4.出队:10 20
    for(int i = 0; i < 2; i++) {
        if(!queue_empty(&queue)) {
            printf("%d ", queue_pop(&queue));
        }
    }
    printf("\n");
    //5.入队: 50 60 30 40
    for(int i = 50; i <= 60; i += 10) {
        if(!queue_full(&queue)) {
            queue_push(&queue, i);
        }
    }
    //6.整体出队
    while(!queue_empty(&queue)) {
        printf("%d ", queue_pop(&queue));
    }
    printf("\n");

    //7.销毁队列
    queue_deinit(&queue);
    return 0;
}