一、数组
问题:(1)统计全班同学的平均身高;(2)获取到全班同学各自的身高。
最无脑的,直接:
float stu1;
float stu2;
float stu3;
...
float stu20;
那此时该如何批量的处理数据?
1***.数组概念: 一组相同类型数据(变量)的集合
1.数组分类
一维整型数组
一维字符型数组
二维整型数组
二维字符型数组
2****.一维整型数组 定义
语法:
类型说明符 数组名[常量表达式]
(1) (2) (3)
(1) 类型说明符 --- 说明这个数组中放的是哪一种类型的数据
(2) 数组名 --- 类似与变量名
通过数组名 代表 数组
数组名:
1.数组名代表的数据类型 -- 整个数组-数组也是一种数据类型
sizeof(a) //a代表的是 整个数组类型
2.数组名代表的值-表示的是数组首元素的地址 也是整个数组的起始地址
//?
//数组名-起名字的规则与变量名起名规则一致
(3).[常量表达式]--- [] //定义时,表示此时定义的是一个数组
常量表达式 --数组长度
所谓数组长度,
指的是这个数组中相同类型的数据的个数
int a[10]; //表示定义了一个包含了10个int型变量的数组
float stu[20]; //直接就批量的相当于定义了20个float类型的变量
float stu[10000];
3.判断数据类型的通用方式:去掉变量名(标识符) 剩下的就是数据类型
int a[10]; //a去掉之后,剩下int[10] 这个称为数组类型
int[10] a;
4.数组的大小:数组大小=sizeof(数据类型)*数组长度
5.数组的初始化和赋值
//初始化
//全部初始化
int a[10] = {1,2,3,4,5,6,7,8,9,10}; //{} 表示 初始化
//部分初始化
int a[10] = {1,2,3,4,5}; //这些值依次给到前面的元素,后边未初始化的元素,默认是0
//未初始化
int a[10]; //此时数组中放的是 随机值(垃圾值)
//数组初始化为0
int a[10] = {};
int a[10] = {0};
6.赋值:
//1.可以通过计算出一些值,赋值到数组中
for (i = 0; i < len; ++i)
{
a[i] = 表达式;
}
//2.通过键盘输入
for (i = 0; i < len; ++i)
{
scanf("%d",&a[i]);
}
7.数组元素引用
方法:
数组名[下标] //此时中括号 表示 数组下标运算
注意:
1).下标
可能会越界 ---编译不报错,这个问题,需要程序员自己小心
2).下标的取值范围
0~数组长度-1
3).数组长度必须是个整型
4).定义时,数组长度可以省略,但是实际长度取决于 初始化元素的个数
int a[] = {1,2}; //必须要初始化 数组长度可以省略,但是必须要初始化
//因为,编译器要根据实际给到的值,推算出数组长度
5).数组 不能整体赋值 不能整体操作 只能操作到具体元素
8.可变长数组:
数据类型 数组名[常量表达式]
c99标准之后,
允许数组长度是一个变量。
注意:
int a[n]; //n是一个变量,不能初始化
//默认是signed int
int a = 0x8000 0000; //负的最小值
1|000 0000 0000 0000 0000 0000 0000 0000 //32个位
1|000 0000 0000 0000 0000 0000 0000 0000 //负0
signed short a = 0x8000;
signed long a = 0x8000000000000000;
9.数组特点:
1.单一性 //数组中元素的类型都是一样的
2.连续性 //数组开辟的是一块连续的内存空间
3.有序性 //元素间是按照顺序存储的
练习:
给定一个数组 (准备10个数据)
对数组进行逆序
// 0 1 2 3 4 5 6 7 8 9 //下标
int a[]={1,2,3,4,5,6,7,8,9,10};//数值
//10,9,8,7,6,5,4,3,2,1
所谓逆序:
对应位置上值交换一下
0号位置 9号位置 //下标相加 为 9 // len - 1
1号位置 8号位置
2号位置 7号位置
3号位置 6号位置
4号位置 5号位置
int i;
a[i] <=> a[9-i];
int temp;
temp = a[i];
a[i] = a[9-i];
a[9-i] = temp;
i 从0~4 //
//两个变量
i 表示从前面往后走 i //0 1 2 3 4
j 表示从后面往前走 j //9 8 7 6 5
-------------------------------------
int i = 0;
for (i = 9; i >= 0; --i)
{
printf("%d\n",a[i]);
}
-------------------------------------
3****.排序:
排序
从小到大 升序
从大到小 降序
规定:
c语言中 统一都是 升序排列
//选择排序
//冒泡排序
//插入排序
//快速排序 //以后再说
求极值 (最大最小)
1.选择排序:
思想:
给对应的位置选择合适的数
2.冒泡排序:
思想:
相邻两个元素,两两比较,
小的放前,大的放后
冒泡排序 对比 选择排序
算法 随着 数据规模的扩展,算法的 时间复杂度的变化
一条条的机器指令 --- CPU运行
O(n) //大o记法
//选择排序
for (j = 0; j < n - 1; ++j)
{
for (i = j + 1; i < n; ++i)
{
if (a[i] < a[j])
{
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
}
//j = 0 i // n-1
//j = 1 i // n-2
...
j = n-2 i //1
1+2+3+...+n-1 // 等差数列
(1 + n-1)*(n-1)/2
n*(n-1)/2
(n^2 - n) /2 // O(n^2)
//冒泡排序
for (j = 1; j < n; ++j)
{
for (i = 0; i < n - j; ++i)
{
if (a[i] > a[i+1])
{
t = a[i];
a[i] = a[i+1];
a[i+1] = t;
}
}
}
j = 1 // n-1
j = 2 // n-2
...
j = n-1 // 1
1+2+...+n-1
3.插入排序:
思想:
将一个数,插入到一个(有序的序列中)
找到合适的位置,然后插入
实现步骤:
1.拿一个要插入的值
2.寻找最终要插入的位置
3.找到后插入数据
//原地插入
for (i = 1; i < n; ++i)
{
int k = a[i];
j = i;
while (j > 0 && a[j-1] > k)
{
a[j] = a[j-1];
--j;
}
a[j] = k;
}
i = 1 //1
i = 2 //2
i = 3 //3
...
i = n-1 //n-1
1+2+...+n-1
它的时间复杂度 n(n^2)
思考:
1.能不能直接a数组中完成插入排序?
4****.查找
//排序 -- 目的 --方便进行查找
//查找的算法
二分查找:
前提:
查找的数据 一定是有序的。
思路:
1.找一个中间位置 mid (实际是数组中间位置的下标 )
判断中间位置上的值 与 要查找的值的大小关系
a[mid] > n
2.a[mid] > n
缩小区间 ,到前面小的一部分继续 二分查找
3.a[mid] < n
缩小区间, 到后面大的一部分继续 二分查找
4.a[mid] == n
直接表示找到了
----------------------------------------------------
5****.一维字符型数组:
char s[10]; //一维字符型数组
//这个数组是用来放,char类型的数据的
练习:
hello --- 大写
c1 c2 c3
//定义一个数组,存放 一个 hello这几个字符
转换成大写输出
1.字符串 //存储字符串数据
特点:
形式上 "hello"
存储上 "hello" -->本质上是按照字符数组的特点存储
"hello" //字符串 --- 一串字符
结束标志 最后会有一个 '\0' 作为结束标志
//好处
有了结束标志,此时字符数组长度其实不重要了。
此时处理字符串时,主要看 '\0'结束标志
2.字符数组:
//初始化它 //全部初始化,部分初始化,未初始化
用字符串初始化
//赋值
//通过表达式给值
for (i = 0; i < n; ++i)
{
s[i] = 'a'+i;
}
//通过输入给值
for (i = 0; i < n; ++i)
{
//scanf("%c",&s[i]);
s[i] = getchar();
}
3.gets()
功能: 给字符数组中,输入一个"字符串"
char *gets(char *s)
char *gets(char s[]) //传一个字符数组的数组名
参数:
s 表示 需要传的是一个 字符数组的 名字
返回值:
表示 存放字符串的 那块空间的地址
注意:
这个函数是危险的,不推荐使用。(一不小心可能就越界了)
fgets(); //这个函数可以解决(后面学)
4.puts()
功能: 将字符串输出,(它会默认输出一个'\n')
int puts(const char *s);
参数:
s //可以是数组名 也可以是 一个字符串常量
返回值:
成功 非负数
失败 -1
eg:
char s[10] = "hello";
puts(s); //数组名
puts("hello"); //字符串常量
注意:
1.数组 主要是用来 存储数据的
2.字符数组,主要是 存储 "字符串" 数据的
练习:
字符串
字符串的长度
"hello"
本质
'h''e''l''l''o''\0' //字符串长度指的是 '\0'前面字符的个数
数组的长度
char s[10];// 数组长度是 10
char s[10] = "hello"; //字符串的长度?
输入一个字符串,
打印出字符串长度
//函数原型
size_t strlen(const char *s);
功能:
统计 给到的字符串的长度
参数:
s //数组名 或 字符串常量
返回值:
表示字符串长度
eg:
char s[] = "hello";
strlen(s); //数组名
strlen("hello"); //字符串常量
//字符串复制
因为字符数组不能整体赋值
char s1[] = "hello";
char s2[10];
s2 = s1 ; //这个操作 c语言中不行
//
while ()
{
//逐个字符操作 复制过去
}
//为了让s2中是字符串
s[i] = '\0';//让最终成为字符串