C语言强化学习第一天(栈与队列)
英文:
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)栈的操作基本原理
/*栈演示代码*/
#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系统三大队列:
消息队列:进程间通信的一种手段
工作队列:延后执行的一种手段
等待队列:随时随地让进程休眠并且让进程随时随地被唤醒
/*队列*/
#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;
}
上一篇: Android JIN编译一直在 build running
下一篇: 小食堂加上窗帘了