数据结构与算法
-
数据结构的一般定义:把现实中大量而复杂的问题以特定的数据类型和特定的存储结构保存到主存中,以及在此基础上实现某个功能(比如查找某个元素,删除某个元素,对所有元素进行排序)而执行的相应操作,这个相应的操作也叫算法。
-
数据结构:
-
狭义:
-
数据结构是专门研究数据存储的问题
-
数据的存储包含两个方面: 个体的存储+个体关系的存储
-
广义:
-
数据结构既包含数据的存储也包含数据的操作
-
对存储数据的操作就是算法
-
算法:
-
狭义:算法和数据的存储方式密切相关
-
广义:算法和数据的存储方式无关,这就是泛型思想。
-
衡量算法的标准:
-
时间复杂度:大概程序要执行的次数,而非执行的时间
-
空间复杂度:算法执行过程中大概所占用的最大内存
-
难易程度
-
健壮性
-
程序 = 数据的存储 + 数据的操作 + 可以被计算机执行的语言
-
指针
-
地址:地址就是内存单元的编号,从0开始的非负整数,范围:0~FFFFFFFF(0~4G-1)。
-
指针:指针就是地址,地址就是指针;指针变量是存放内存单元地址的变量;指针的本质是一个操作受限的非负整数。
-
分类:
-
基本类型的指针
-
注意:指针变量也是变量,只不过它存放的不能是内存单元的内容,只能存放内存单元的地址;普通变量前不能加*;常量和表达式前不能加&。
示例1:
//p保存i的地址, 那么p就指向i;
//修改p的值不影响i的, 修改i的值不影响p的值;
//*p就代表了i, 因为p指向了i;
#include <stdio.h>
int main(void)
{
int* p; //p是个变量名字, int *表示该p变量只能存储int变量的地址
int i = 10;
int j;
p = &i; //int *p = &i; 等价于 int *p; p = &i;
j = *p; //等价于j = i;
printf("i = %d, j = %d, *p =%d\n", i, j, *p); //结果都是10
return 0;
}
-
如何通过被调函数修改主函数中普通变量的值:
-
实参为相关变量的地址
-
形参为以该变量的类型为类型的指针变量
-
在被调函数中通过 *形参变量名 的方式就可以修改主函数中普通变量的值
示例2:
#include <stdio.h>
void f(int* p)
{
*p = 100;
}
int main(void)
{
int i = 9;
f(&i);
printf("i = %d", i);
return 0;
}
-
指针和一维数组的关系
-
数组名:一维数组名是个指针变量;它存放的是一维数组第一个元素的地址;它的值不能被改变;一维数组名指向的是数组的第一个元素。
-
下标和指针的关系:a[i] <<==>> *(a + i)
-
指针变量的运算:指针变量不能相加,不能相乘,不能相除;如果两指针变量属于同一个数组,则可以相减;指针变量可以加减一个整数。
p + i的值是p + i*(p所指向的变量所占的字节数)
p - i的值是p - i*(p所指向的变量所占的字节数)
p++ <==> p + 1
p-- <==> p - 1
示例1:
#include <stdio.h>
int main(void)
{
int a[5] = { 1, 2, 3, 4, 5 };
//a[3] == *(3 + a);
printf("%p\n", a + 1);
printf("%p\n", a + 2);
printf("%d\n", *a + 3); // *a + 3 等价于 a[0] + 3
return 0;
}
-
如何通过被调函数修改主函数中一维数组的内容:
-
两个参数
-
存放数组首元素的指针变量
-
存放数组元素长度的整型变量
示例2:
#include <stdio.h>
void Show_Array(int* p, int len)
{
int i = 0;
for (i = 0; i < len; i++)
printf("%d\n", p[i]);
//p[2] = -1; //p[2] == *(p+2) == *(a+2) == a[2]
//p[i]就是主函数的a[i]
}
int main(void)
{
int a[5] = { 1, 2, 3, 4, 5 };
Show_Array(a, 5); //a 等价于 &a[0], &a[0]本身就是int *类型
//printf("%d\n", a[0]);
return 0;
}
-
结构体
-
定义:结构体是用户根据实际需要自己定义的复合数据类型。
-
使用结构体的两种方式:
-
st.sid
-
pst->sid:pst所指向的结构体变量中的sid这个成员
示例1:
#include <stdio.h>
#include <string.h>
#define _CRT_SECURE_NO_WARNINGS
struct Student
{
int sid;
char name[200];
int age;
}; //分号不能省
int main(void)
{
struct Student st = { 1000, "zhangsan", 20 };
printf("%d %s %d", st.sid, st.name, st.age);
st.sid = 99;
//st.name = "lisi"; //error
strcpy(st.name, "lisi");
st.age = 22;
printf("%d %s %d", st.sid, st.name, st.age);
//printf("%d %s %d", st); //error
return 0;
}
示例2:
#include <stdio.h>
struct Student
{
int sid;
char name[200];
int age;
}; //分号不能省
int main(void)
{
struct Student st = { 1000, "zhangsan", 20 };
st.sid = 99; //第一种方式
struct Student* pst;
pst = &st;
pst->sid = 99; //第二种方式 pst->sid 等价于 (*pst).sid, 而 (*pst).sid 等价于 st.sid, 所以 pst->sid 等价于 st.sid
return 0;
}
-
注意事项:结构体变量不能加减乘除,但可以相互赋值;普通结构体变量和结构体指针变量作为函数传参的问题。
示例3:
#include <stdio.h>
#include <string.h>
#define _CRT_SECURE_NO_WARNINGS
struct Student
{
int sid;
char name[200];
int age;
}; //分号不能省
void f(struct Student* pst);
void g1(struct Student st);
void g2(struct Student* pst);
int main(void)
{
struct Student st; //已经为st分配好了内存
f(&st); //输入
g1(st); //输出
g2(&st); //输出
return 0;
}
void f(struct Student* pst)
{
(*pst).sid = 1000;
strcpy((*pst).name, "zhangsan");
(*pst).age = 22;
}
//这种方式耗内存 耗时间 不推荐
void g1(struct Student st)
{
printf("%d %s %d", st.sid, st.name, st.age);
}
void g2(struct Student* pst)
{
printf("%d %s %d", pst->sid, pst->name, pst->age);
}
-
动态内存的分配和释放
示例1:
#include <stdio.h>
#include <malloc.h>
#define _CRT_SECURE_NO_WARNINGS
int main(void)
{
int a[5] = { 4, 10, 2, 8, 6 }; //静态分配
int len, i;
printf("请输入你需要分配的数组的长度: len = ");
scanf("%d", &len);
int* pArr = (int*)malloc(sizeof(int) * len); //malloc函数返回第一个字节地址(干地址), 强制类型转换指明是整型类型(占四个字节)的第一个字节地址
//*pArr = 4; //类似于a[0] = 4;
//pArr[1] = 10; //类似于a[1] = 1000;
//printf("%d %d\n", *pArr, pArr[1]);
//我们可以把pArr当做一个普通数组来使用
for (i = 0; i < len; ++i)
scanf("%d", &pArr[i]);
for (i = 0; i < len; ++i)
printf("%d", *(pArr + i));
free(pArr); //把pArr所代表的动态分配的字节的内存释放
return 0;
}
示例2:
#include <stdio.h>
#include <malloc.h>
struct Student
{
int sid;
int age;
};
struct Student* CreateStudent(void);
void ShowStudent(struct Student*);
int main(void)
{
struct Student* ps;
ps = CreateStudent();
ShowStudent(ps);
return 0;
}
void ShowStudent(struct Student* pst)
{
printf("%d %d", pst->sid, pst->age);
}
struct Student* CreateStudent(void)
{
struct Student* p = (struct Student*)malloc(sizeof(struct Student));
p->sid = 99;
p->age = 88;
return p;
}
以上内容来源于小破站:郝斌数据结构入门