数据结构概述
数据结构
定义
我们如何把现实中大量而复杂的问题以特定的数据类型和特定的存储结构保存到主存储器(内存)中,以及在此基础上为实现某个功能(比如查找某个元素,删除某个元素,对所有元素进行排序)而执行的相应操作,这个相应的操作也叫算法
数据结构 = 个体的存储 + 个体的关系存储
算法 = 对存储数据的操作
算法
解题和方法和步骤
衡量算法的标准
- 时间复杂度:大概程序要执行的次数,而非执行的时间
- 空间复杂度:算法执行过程中大概所占用的最大内存
- 难易程度
- 健壮性
数据结构是软件中最核心的课程
程序 = 数据的存储 + 数据的操作 +可以被计算机执行的语言
预备知识
指针
指针重要性:指针是C语言的灵魂
定义
地址
内存单元的编号
从0开始的非负整数
指针就是地址,地址就是指针
指针变量是存放内存单元地址的变量
指针的本质是一个操作受限的非负整数
分类
1.基本类型的指针
int main(void) { int* p; int i = 10; int j; p = &i; j = *p; //等价于j = i printf("i = %d, j = %d,*p = %d", i, j, *p); return 0; }
修改主函数变量的值
# include <stdio.h> void f(int * p) //不是定义了一个名字叫做*p的形参,而是定义了一个形参,该形参名字叫做p,它的类型是int * { *p = 100; } int main(void) { int i = 9; f(&i); printf("i=%d\n", i); return 0; }
2.指针和数组的关系
# include <stdio.h> int main(void) { int a[5] = { 1,2,3,4,5 }; 3[a] == *(3 + a); //等价于 a[3]==*(a+3) printf("%d\n", 3[a]); printf("%p\n", a + 1); //00000081EEEFF83C printf("%p\n", a + 2); //00000081EEEFF840 printf("%p\n", a + 3); //00000081EEEFF844 %p以十六进制输出 printf("%d\n", *a + 3); //*a等价于a[0] 1+3=4 return 0; }
3.多级指针
# include <stdio.h> void f(int**); int main(void) { int i = 9; int* p = &i; printf("%p\n", p); f(&p); printf("%p\n", p); } void f(int** q) { *q = (int*)0xFFFFFFFF; }
结构体
为什么会出现结构体
为了表示一些复杂的数据,而普通的基本类型变量无法满足需求
什么叫结构体
结构体是用户根据实际需要自己定义的复合数据类型
如何使用结构体
两种方式:
struct Student st = { 1000,"张三",20 };
struct Student * pst;
- st.sid
- pst->sid:pst所指向的结构体变量中的sid这个成员
# include <stdio.h> # include <string.h> struct Student { int sid; char name[200]; int age; }; int main(void) { struct Student st = { 1000,"张三",20 }; printf("%d %s %d\n", st.sid, st.name, st.age); st.sid = 99; strcpy_s(st.name , "李四"); st.age = 22; printf("%d %s %d\n", st.sid, st.name, st.age); return 0; }
第二种方式
# include <stdio.h> struct Student { int sid; char name[100]; int age; }; int main(void) { struct Student st = { 1000,"张三",20 }; //st.sid=99; //第一种方式 struct Student * pst; pst = &st; pst->sid = 99; //pst->sid等价于(*pst).sid 而(*pst).sid等价于st.sid 所以pst->sid等价于st.sid }
注意事项
结构体变量不能加减乘除,但可以相互赋值
普通结构体变量和结构体指针变量作为函数传参的问题
1 #include <stdio.h> 2 #include <string.h> 3 4 void f(struct Student*); 5 void g(struct Student*); 6 7 struct Student 8 { 9 int sid; 10 char name[200]; 11 int age; 12 }; 13 14 int main(void) 15 { 16 struct Student st; 17 int i; 18 19 f(&st); 20 //g(st); 21 g(&st); 22 23 return 0; 24 } 25 26 void f(struct Student* pst) 27 { 28 (*pst).sid = 99; 29 strcpy_s(pst->name, "张三"); 30 pst->age = 22; 31 } 32 33 void g(struct Student* pst) 34 { 35 printf("%d %s %d\n", pst->sid, pst->name, (*pst).age); 36 } 37 38 //这种方式耗内存 耗时间 不推荐 39 void g(struct Student st) 40 { 41 printf("%d %s %d\n", st.sid, st.name, st.age); 42 }
动态内存的分配和释放
# define _CRT_SECURE_NO_WARNINGS 1 # include <stdio.h> # include <malloc.h> int main(void) { int a[5] = { 4,10,2,8,6 }; int len; printf("请输入你需要分配的数组的长度:len="); scanf("%d", &len); int* pArr = (int*)malloc(sizeof(int) * len); *pArr = 4; //类似于a[0]=4; pArr[1] = 10; //类似于a[1]=10; printf("%d %d", *pArr, pArr[1]); for (int i = 0;i < len;i++) { scanf("%d", &pArr[i]); } for (int i = 0;i < len;i++) printf("%d\n" ,*(pArr + i)); free(pArr); //把pArr所代表的动态分配的20个字节的内存释放 }
跨函数使用内存
1 # include <stdio.h> 2 # include <malloc.h> 3 4 struct Student 5 { 6 int sid; 7 int age; 8 }; 9 10 struct Student* CreateStudent(void); 11 void ShowStudent(struct Student*); 12 13 int main(void) 14 { 15 struct Student* ps; 16 17 ps = CreateStudent(); 18 ShowStudent(ps); 19 20 return 0; 21 } 22 23 void ShowStudent(struct Student *pst) 24 { 25 printf("%d %d\n", pst->sid, pst->age); 26 } 27 28 struct Student* CreateStudent(void) 29 { 30 struct Student* p = (struct Student*)malloc(sizeof(struct Student)); 31 p->sid = 99; 32 p->age = 88; 33 return p; 34 }