day1:
day2:
内存空间空间划分,动态申请空间malloc free
typedef,结构体[普通结构体,结构体数组,结构体指针]
共用体
day3:顺序表【增删改查】
day4:
day5:链表:单向链表,单向循环,双向链表,双向循环链表【没有上限】
day6 :栈【增删】,队列【增删】,哈希查找,折半查找
day7:排序算法:交换排序(快速排序),选择排序(简单选择排序,堆排序),插入排序(直接插入排序,希尔排序),归并排序(二路归并,多路归并),基数排序
二叉树【创建,遍历】
数据结构补习
一,内存空间划分
内核
用户空间:
栈区:由计算机分配空间,计算自动释放空间
栈区:需要满足栈的特点,先进后出,后进先出
堆区:由程序员手动申请空间,手动释放空间 malloc free
堆区:满足队列的特点,先进先出,后进后出(先定义变量,先分配空间)
栈区和堆区没有明确的分界点,直到栈区和堆区的地址重合
静态区:存储全局变量和静态变量
.bss:存储未初始化的静态变量或全局变量
.data:存储已经初始化的静态变量或全局变量
.ro:存储常量,字符串常量,const修饰的全局变量
.txt 文本段,存储二进制文件
二,动态申请和释放空间
动态申请:
头文件:#include<stdlib.h>
格式:void *malloc(size_t size);
返回值:当在堆区申请失败默认返回NULL;如果申请成功,默认返回堆区空间首地址
注意在使用时必须保存堆区的首地址,方便后期空间释放,否则会造成空间泄露问题。
参数:size_t size size_t: unsigened int
申请空间大小字节
使用格式:
1.单个分配空间
int *p=(int *)malloc(sizeof(int));
注意:p和q只是一个简单的指针,不可以偏移
2.多个空间申请
int *p=(int *)malloc(sizeof(int)*5);
注意:当申请多个空间时,就可以指针偏移
动态释放:
头文件:#include<stdlib.h>
格式:void free(void *ptr);
返回值:无返回值函数
参数:void *ptr;需要释放空间的指针
使用格式:
free(p);//释放:堆区的空间不被p指向,但是空间还在
p=NULL;//防止p为野指针
野指针:
1.直接使用未初始化的指针
2.指针指向数组,通过指针越界访问
3.当遇到指针函数返回局部变量的地址
int *fun()
{
int arr[3];
return arr;//因为arr是局部变量,调用函数分配空间 函数调用结束 函数调用结点空间释放,当返回地址时,就是野指针
}
4.指向堆区的空间,释放空间以后,就是野指针
free(p)
//主函数.c 写主函数
#include "3.h"
int main(int argc,const char *argv[])
{
int n;
puts("请输入想输入的数字个数:");
scanf("%d",&n);
char *str=create_str(n);
char *str1=create_str(n);
puts("str:");
scanf("%s",str);
puts("str1:");
scanf("%s",str1);
printf("%d\n",Mystrcmp(str,str1));
str=Free_space(str);
str1=Free_space(str1);
return 0;
}
//.c文件 写自定义函数
#include "3.h"
char *create_str(int n)
{
char *p=(char *)malloc(sizeof(char)*n);
if(p==NULL)
{
return NULL;
}
return p;
}
int Mystrcmp(const char *p,const char *q)
{
while(*p&&*p==*q)
{
p++;
q++;
}
return *p-*q;
}
char *Free_space(char *p)
{
if(p==NULL)
return NULL;
free(p);
p==NULL;
return p;
}
//.h文件 声明函数 声明头文件
#ifndef N
#define N
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char *create_str(int n);
int Mystrcmp(const char *p,const char *q);
char *Free_space(char *p);
#endif
三,类型重定义typedef
作用:起别名,起小名
格式:typedef 数据类型 别名;
数据类型:基本类型 构造类型 指针 空类型
别名:满足命名规范,可以是多个
int a=10;#
3.1类型推导
3.2 宏和类型重定义的区别
typedef int size_4 等价 #define size_4 int
1>宏只属于宏替换,类型重定义属于类型重定义
2>宏不属于C语句,类型重定义属于C语句
3>宏在预处理阶段,类型重定义在编译阶段
4>宏只可以做简单类型的替换,但是类型重定义可以重定义任意一种类型
四,结构体struct
结构体:用来存储多个相同或不同类型元素的构造数据类型
构造类型:可以拆分
int arr[3]={1,2,3}
定义格式: struct 结构体名
{
数据类型 成员1;
数据类型 成员2;
...
数据类型 成员n;
};
1.struct:结构体的关键字
2.结构体名:满足命名规范 可有可无
3.{ }不可省略
4.数据类型:基本类型 构造类型 指针 空
5.成员变量的个数任意
6.结构体后面的分号必须存在
7.结构体的描述位置任意,一般在全局
8,结构体描述 计算机不分空间 直到定义结构体变量才分配
4.1结构体普通变量
直接定义(可省略结构体名)/间接定义(不可省略结构体名)
1.按顺序初始化
2.不按顺序初始化
3.定义结构体变量
4.结构体输入输出
//四种初始化结构体变量的方式 stu1 stu2 stu3 stu4
#include <stdio.h>
#include<string.h>
//结构体在引用成员时,必须使用结构体变量加“.”区进行调用
struct student
{
char name[20];
int age;
float score;
char sex;
}stu1={"金一",12,100,'m'},
stu2={.age=11,.name="二金"},
stu3,stu4;
void output(struct student stu)
{
printf("name=%s,age= %d,score=%f,sex= %c\n",stu.name,stu.age,stu.score,stu.sex);
}
int main(int argc,const char *argv[])
{
strcpy(stu3.name,"三金");
stu3.age=22;
stu3.score=99;
stu3.sex='w';
puts("请输入姓名 年纪 成绩 性别:");
scanf("%s",stu4.name);
scanf("%d",&stu4.age);
scanf("%f",&stu4.score);
scanf(" %c",&stu4.sex);
output(stu1);
output(stu2);
output(stu3);
output(stu4);
return 0;
}
4.2结构体数组
4.2.1定义结构体同时定义变量,并初始化
struct student
{
char name[20];
int age;
float score;
char sex;
}arr1[2]={"金一",12,100,'m',"金二",13,91,‘m'’},【多使用】
arr2[2]={{"金一",12,100,'m'},{"金二",13,91,‘m’}},
arr3[2]={[0]={"金一",12,100,'m'},[1]={"金二",13,91,‘m’}},
arr4[2]={[0]={.name="金一",.age12},[1]={age=12}},//不按顺序初始化
struct student
{
char name[20];
int age;
float score;
char sex;
}arr[2];
arr[0]//表示第一个人所有信息
arr[0].name//表示第一个人的姓名
arr[1].sex//表示第二个人的性别
strcpy(arr[0].name,"李四")
结构体数组循环输入输出
struct student
{
char name[20];
int age;
float score;
char sex;
}arr[2];
for(int i=0;i<2;i++)
{
scanf("%s",arr[i].name);
scanf("%d",&arr[i].age);
scanf("%f",&arr[i].score);
scanf(" %c",&arr[i].sex);
}
#include <stdio.h>
#include<string.h>
struct student
{
char name[20];
int age;
float score;
char sex;
};
void output(struct student stu[])
{
int i;
for(i=0;i<2;i++)
printf("name=%s,age= %d,score=%f,sex= %c\n",stu[i].name,stu[i].age,stu[i].score,stu[i].sex);
}
int main(int argc,const char *argv[])
{
struct student stu1[2]={[0]={"金一",12,100,'m'},[1]={.age=11,.name="二金"}},
stu2[2]={"金三",11,91,'w',"金四",12,100,'m'},
stu3[2],stu4[2];
strcpy(stu3[0].name,"5金");
stu3[0].age=23;
stu3[0].score=88;
stu3[0].sex='w';
strcpy(stu3[1].name,"6金");
stu3[1].age=24;
stu3[1].score=89;
stu3[1].sex='w';
puts("请输入姓名 年纪 成绩 性别:");
int i;
for(i=0;i<2;i++)
{
scanf("%s",stu4[i].name);
scanf("%d",&stu4[i].age);
scanf("%f",&stu4[i].score);
scanf(" %c",&stu4[i].sex);
}
output(stu1);
output(stu2);
output(stu3);
output(stu4);
return 0;
}
4.2.2定义结构体后定义变量,并初始化
#include <stdio.h>
#include<string.h>
struct car
{
char brand[20];
int price;
char color;
};
void input(struct car str[])
{
int i;
for(i=0;i<5;i++)
{
puts("请输入 牌子 价格 颜色:");
scanf("%s",str[i].brand);
scanf("%d",&str[i].price);
scanf(" %c",&str[i].color);
}
}
void output(struct car str[])
{
int i;
for(i=0;i<5;i++)
printf("brand=%s,price= %d,color= %c\n",str[i].brand,str[i].price,str[i].color);
}
void maxprice(struct car str[])
{
int max=0;
int i;
for(i=1;i<5;i++)
{
if(str[i].price>str[max].price)
max=i;
}
printf("最贵的品牌和车子价格为:%s,%d元\n",str[max].brand,str[max].price);
}
void maopao(struct car str[])
{
int i,j;
struct car temp;
for(i=0;i<4;i++)
{
for(j=0;j<4-i;j++)
if(str[j].price>str[j+1].price)
{
temp=str[j];
str[j]=str[j+1];
str[j+1]=temp;
}
}
}
int main(int argc,const char *argv[])
{
struct car str[5];
input(str);
maxprice(str);
maopao(str);
output(str);
return 0;
}
4.3 结构体指针
结构体指针使用->调用
地址使用-> 值使用.
struct student
{
char name[20];
int age;
float score;
char sex;
}*p;//直接定义
struct student *p;//间接定义
2>指针的使用
2.1 结构体指针指向普通变量的地址
struct student stu={"张三",14,100,‘w'};
struct student *p=&stu;
p->name等价于 stu.name;表示名字((*p).name &stu->name)
p->sex 等价于stu.sex:表示性别
#include <stdio.h>
struct student
{
char name[20];
int age;
float score;
char sex;
};
int main(int argc,const char *argv[])
{
struct student stu={"张三",14,100,'W'};
struct student *p=&stu;
//地址使用->,应用成员变量
//值使用.应用成员变量
printf("%s %d %.2f %c\n",p->name,p->age,p->score,p->sex);
printf("%s %d %.2f %c\n",stu.name,stu.age,stu.score,stu.sex);
printf("%s %d %.2f %c\n",(*p).name,p->age,p->score,p->sex);
return 0;
}
2.2 结构体指针指向结构体数组的首地址
struct student stu[2]={“李四“,12,98,'m',"小王",15,100,'w'};
struct student *p=stu;
for(int i=0;i<2;i++)
{
printf("%s %d %f %c",(p+i)->name,(p+i)->age,(p+i)->score,p->sex);
}
2.3 结构体指针指向堆区的空间【重点】
int *p=(int *)malloc(sizeof(int));
//结构体指针指向单个的结构体空间
struct student *p=(struct student *)malloc(sizeof(struct student));
//结构体指针指向连续的结构体空间
struct student *p=(struct student *)malloc(sizeof(struct student)*5);
查找一个字符串相同结构体成员,并输出
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student
{
char name[20];
int age;
float score;
char sex;
};
struct student *create(int n)
{
struct student *p=(struct student *)malloc(sizeof(struct student)*n);
if(p==NULL)
return NULL;
return p;
}
void input(struct student *p,int n)
{
int i;
for(i=0;i<n;i++)
{
puts("name:");
scanf("%s",(p+i)->name);
puts("age:");
scanf("%d",&(p+i)->age);
puts("score:");
scanf("%f",&(p+i)->score);
puts("sex:");
scanf(" %c",&(p+i)->sex);
}
}
void output(struct student *p,int n)
{
int i;
for(i=0;i<n;i++)
{
printf("%s\t%d\t%.2f\t%c\n",(p+i)->name,(p+i)->age,(p+i)->score,(p+i)->sex);
}
}
int serc(struct student *p,int n)
{
int i;
char str[20];
puts("请输入你想找的名字:");
scanf("%s",str);
for(i=0;i<n;i++)
if(strcmp((p+i)->name,str)==0)
{
return i;
}
return -1;
}
int main(int argc,const char *argv[])
{
struct student *p=create(5);
input(p,5);
output(p,5);
int i=serc(p,5);
if(i==-1)
{
printf("错误,没找到\n");
}
else
printf("你想找的学生信息:%s\t%d\t%.2f\t%c\n",(p+i)->name,(p+i)->age,(p+i)->score,(p+i)->sex);
}
4.4 结构体引用
1>普通结构体变量时使用. 引用
2>结构体数组需要结构体数组名加.引用
3>结构体指针,需要使用“->”引用
4>结构体变量不可以整体输出,常用来实现交换,或者做参数实现传递
4.5 typedef和结构体结合
typedef struct student
{
char name[20];
int age;
}stu,stu_arr[3],*stu_p;
stu a;
stu arr[3] --->stu [3]
stu *p
4.6普通结构体嵌套
//定义一个人:姓名,年龄,出生年月日
typedef struct Birth
{
int year;
int month;
int day;
}bir;
typedef struct person
{
char name[10];
int age;
bir birth;
}per;
per a;-->struct person a;
4.7结构体嵌套结构体数组
typedef struct //结构体名可以不写
{
char name[10];
int price;
char color[20];
}car;
typedef struct person
{
char name[10];
int age;,
car arr[3];
}per;
per a={"张三',14,“大众”,111111,“黑色”,“宝马”,222222,“黄色”,“奔驰,333333,“绿色”}
打印大众 a.arr[0].name
typedef struct
{
char name[10];
int price;
char color[10];
}car;
typedef struct student
{
char name[20];
int age;
float score;
char sex;
car c[3];
}*stu_p,stu_t;
int main(int argc,const char *argv[])
{
int i;
stu_t a={"张三",12,100,'m',"DZ",10000,"YELLOW","BC",12222,"BLUE","BYD",11111,"BLACK"};
for(i=0;i<3;i++)
{
printf("%s\t%d\t%s\n",a.c[i].name,a.c[i].price,a.c[i].color);
}
}
4.8 结构体存储空间【重点】
64位操作系统
1>结构体变量的地址是结构体第一个成员的首地址
2>结构体每个成员的地址是连续的
3>结构体的大小等于各个成员的总和
4>满足字节对齐原则:
1.结构体的总字节数是最宽成员的整数倍,否则使用空字节填充
2.结构体的首地址是最宽成员的整数倍
3.结构体各个成员的偏移量是该成员字节大小的倍数,否则使用空字节填充
偏移量:该成员的地址编号到起始地址之间的差
如果成员是char,则偏移量是1的倍数
如果成员short,则偏移量是2的倍数
如果成员是 int float 则偏移量是4的倍数
如果成员是double long 指针则偏移量是8的倍数
32位操作系统
满足字节对齐原则:
1>结构体变量的地址是结构体第一个成员的首地址
2>结构体每个成员的地址是连续的
3>结构体的大小等于各个成员的总和
4>满足字节对齐原则:
1.结构体的总字节数是最宽成员的整数倍,否则使用空字节填充
2.结构体的首地址是最宽成员的整数倍
3.结构体各个成员的偏移量是该成员字节大小的倍数,否则使用空字节填充
偏移量:该成员的地址编号到起始地址之间的差
如果成员是char,则偏移量是1的倍数
如果成员short,则偏移量是2的倍数
如果成员是 int float double long 指针则偏移量是4的倍数
4.9 共用体union
共用体:存储类型相同或不同的构造类型
特点:成员共用一片空间
1>共用体的各个成员占用同一片空间
2>共用空间
4.9.1共用体定义和初始化
1>直接和间接定义和初始化
union
{
int a;
char c;
float b;
}value;
4.9.2结构体和共用体结合
1>共用体在结构体外嵌套
2>共用体在结构体内嵌套
#include <stdio.h>
/*typedef union
{
float score;
char postion[20];
}u;*/
typedef struct
{
char name[20];
char sex;
char job;
union
{
float score;
char postion[20]
};
}a;
int main(int argc,const char *argv[])
{
// a value1={"金日成",'M','s',.value.score=100};
a value1={"金小城",'M','T',.postion="数学老师"};
printf("%s\t%c\t%c\t%s\n",value1.name,value1.sex,value1.job,value1.postion);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
char name[20];
char sex;
char job;
union
{
float score;
char postion[20]
};
}a,*p,per[5];
p create(int n)
{
p q=(p)malloc(sizeof(a)*n);
if(q==NULL)
return NULL;
return q;
}
void input(p q,int n)
{
int i;
for(i=0;i<n;i++)
{
puts("请输入姓名:");
scanf("%s",(q+i)->name);
puts("请输入性别:");
scanf(" %c",&((q+i)->sex));
puts("请输入身份:");
scanf(" %c",&((q+i)->job));
if((q+i)->job=='t')
{ puts("请输入职位:");
scanf("%s",(q+i)->postion);}
else{
puts("请输入成绩:");
scanf("%f",&((q+i)->score));
}
}
}
void output(p q,int n)
{
int i;
for(i=0;i<n;i++)
if((q+i)->job=='t')
printf("%s\t%c\t%c\t%s\n",(q+i)->name,(q+i)->sex,(q+i)->job,(q+i)->postion);
else
printf("%s\t%c\t%c\t%.2f\n",(q+i)->name,(q+i)->sex,(q+i)->job,(q+i)->score);
}
void average(p q,int n)
{
int i,count=0;
float sum=0;
for(i=0;i<n;i++)
if((q+i)->job=='s')
{
sum+=(q+i)->score;
count++;
}
printf("average=%.2f\n",sum/count);
}
void number(p q,int n)
{
int i,count=0;
for(i=0;i<n;i++)
if((q+i)->job=='t')
count++;
printf("老师个数=%d\n",count);
}
int main(int argc,const char *argv[])
{
p arr=create(5);
input(arr,5);
output(arr,5);
average(arr,5);
number(arr,5);
free(arr);
arr=NULL;
return 0;
}