0.问题的引入
int a,b;
如果我们需要定义100个整型变量;
int a1,a2,a3,a4...a99;
很明显上面这种定义很多个相同类型变量的方法,不人道,.....
有没有办法我们可以一次定义一组相同类型的变量呢?
数组
1.什么是数组?
一组具有相同类型的数据元素的有序集合。
在C语言中,数组:
一维数组
二维数组
三维数组
四维数组
五维数组
....
其实,C语言中只有一维数组。
2.一维数组
2.1定义格式
类型说明符 数组名[整型表达式]{={初始化列表}};
类型说明符
指定数组中元素的类型,而不是数组的类型!!!!!
可以C语言中任何合法的类型
{基本类型,构造类型,指针类型...}
数组名
对象的名字。“标识符”
整型表达式
指定数组中元素的个数
C语言规定在定义数组的时候,需要指定
(隐含指定->编译器可以推断出)
数组元素的个数
“常量表达式”
例子:
int a[10];//定义了数组,名为a,里面含有10个int类型的元素
int 是数组元素的类型 不是数组的类型!!!!!
typeof(a):a的类型
a是一个含有10个int类型元素的数组
int[10]
上面的这个代码,不仅定义了一个数组a,同时还声明了
一个新的构造类型
typeof(a) ==> int [10]
假设让你顶一个和对象a一样的类型的对象b,该如何定义呢?
类型说明符 变量名;
typeof(a) b;
int[10] b;
==>int b[10];
2.2 一维数组元素的引用
int a[10];//定义了一个数组,名为a,里面含有10个int类型的元素。
a中有10个 int类型的元素,如何访问这些元素呢?引用它
引用数组元素:
数组名[下标]
下标:C语言约定数组元素的下标是从0开始的
0,1,2,3,4,...n-1
如:
a[0]
a[1]
a[2]
..
a[9]
typeof(a[0]) ==> int
引用数组元素和引用普通的变量是一模一样的。
数组元素也有左值和右值。
int a[10];
int b;
a[0] = 1024;//把数值1024赋值给 元素a[0]
//把数值1024存放到元素a[0]的地址中去
//a[0]代表的元素a[0]的左值:lvalue,地址。
b=a[0];//把a[0]的值,赋值给b
//a[0]代表的是元素a[0]的右值,rvalue,对象的值
scanf("%d",&b);
scanf("%d",&a[0]);
2.3一维数组在内存中的存放
在C语言中,我们用一组地址连续的储存空间,从低地址到高地址
一次存放数组中的每个元素的
a[0]的后面是a[1];
a[1]的后面是a[2];
..
eg:
int a[10]
0x3000 |_ _ _ _ | a[0]
0x3004 |_ _ _ _ | a[1]
0x3008 |_ _ _ _ | a[2]
..
例子:
假设在32bits的机器上,int 占32bits
int a[10];
&a[0] == 0x4000
==>&a[1] == 0x4004
&a[2] == 0x4008
...
&a[i] == &a[0]+sizeof(a[0])*i;
2.4一维数组的初始化
初始化是指:定义对象时,就指定对象的值
数组的初始化用{}
a.int a[10]={1,2,3,4,5,6,7,8,9,10};
==>
a[0]==1;
a[1]==2;
a[2]==3;
...
2.可以只对初始元素初始化,后面的元素自动初始化为0
int a[10] = {1,2,3};
=>
a[0]==1;
a[1]==2;
a[2]==3;
a[3]==0;
a[4]==0;
...
3.如果对全部数组元素都赋初始值,在定义数组时候,可以不指定
数组的长度,因为编译器很聪明,它可以算出你有多少个元素
int a[]={1,2,3,4,5}; ==> int a[5]={1,2,3,4,5};
==>数组a有5个元素。
NOTE:
只可以在定义数组的时候,指定数组全部元素的值
int a[5]={1,2,3,4,5};正确
int a[5];
a[5]={1,2,3,4,5};error
a={1,2,3,4,5};error
不能对数组进行整体赋值,只允许在定义数组时候,指定整体的初始值!!
练习:
1.定义一个一维数组,并通过键盘一一对元素进行输入。
2.定义一个int类型的数组,并从键盘中随机输入每个元素,
求该一维数组的元素之和,最大值,最小值。
3.判断一个一维数组是否递增
int a[10];
a[0]<=a[1]<=a[2]....
a[0]>a[1]
a[1]>a[2]
....
a[i]>a[i+1]
4.排序
把每一个元素按一定的规则(升序或降序)放置到合适的位置上去。
冒泡法:
相邻两个元素,两两比较,把较大者往后挪(两两交换)
int a[N];//#define N 10
if(a[0]>a[1])
{
a[0]<-->a[1];
}
if(a[1]>a[2])
{
a[1]<-->a[2];
}
....
if(a[i]>a[i+1])
{
a[i]<-->a[i+1];
}
-------
//一趟冒泡,把最大值 ---> a[N-1]
for(i=0;i<N-1;i++)
{
if(a[i]>a[i+1)
{
//交换
int t;
t = a[i];
a[i]=a[i+1];
a[i+1]=t;
}
}
===>
进行N-1次冒泡,就可以把所有的元素都放置在合适的位置上了?
t来表示冒泡的次数
t表示第t次冒泡 最后一个元素
t == 0 i<N-1
t == 1 i<N-2
... ...
t i<N-1-t
for(t=0;t<N-1;t++)
{
for(i=0;i<N-1-t;i++)
{
if(a[i]>a[i+1)
{
//交换
int t;
t = a[i];
a[i]=a[i+1];
a[i+1]=t;
}
}
}
选择法排序:
a.选择一个最大的元素
b.把最大的元素与最后的一个位置进行选择
int max=a[0];//记录最大值
int i_max=0;//记录最大值的下标
for(i=0;i<N;i++)
{
if(a[i]>max)
{
max=a[i];
i_max=i;
}
}
a[i_max]<-->a[N-1];
if(i_max!=N-1)
{
t=a[i_max];
a[i_max]=a[N-1];
a[N-1]=t;
}
------------------
for(i=0;i<N-1;i++)
{
if(a[i]>max)
{
max=a[i];
i_max=i;
}
}
a[i_max]<-->a[N-1-1];
if(i_max!=N-1-1)
{
t=a[i_max];
a[i_max]=a[N-1-1];
a[N-1]=t;
}
-----------------------
冒泡 VS 选择
冒泡:
两两比较 两两交换
N个元素
一趟冒泡
在最坏的情况,可能交换N-1次 ==> N(N-1)
在最好的情况下(本身就是有序的),交换0次
O(n^2)
选择:
先选择最大值,与最后那个元素进行交换
N个元素
每一次选择完成后,都会交换一次
最多交换N-1次 ==>N(N-1)
O(n^2)
5.查找一个元素
在数组a[N]中查找一个元素x,如果找到返回其下标没有找到返回-1
1)查找可以用遍历
for(i=0;i<N;i++)
{
if(a[i] == x)
{
//找到了
return i;
}
}
return -1;
2)在一个有序数组中查找,用遍历,就显的很low
“二分查找法/折半查找法”
假设待查找元素的下标范围为:
[low,high]
low = 0;
high = N-1;
while(low<=high)
{
//中间元素下标
mid = (low+high)/2;
if(x==a[mid])
{
//找到了,退出循环
}
else if(x>a[mid])
{
//待查查的元素的下标范围[mid+1,high]
low = mid+1;
}
else
{
//待查找的元素的下标范围[low,mid-1]
//x<a[mid]
high = mid-1;
}
}
if(...)
....
作业:
1.先手写选择和冒泡排序(包括图,思路,代码),然后在执行
要求:必须有注释!!!!(不用发邮箱)
2.求斐波拉契数列数列前20项的和
fibonacci
1 1 2 3 5 8 13....
3.不用排序,把一个数组中的负数放在数组的前面
如:
2 4 -3 5 -4 8 -2
=>
...
4.求一个一维数组中的第二大元素,不用排序
跟着老大走你就是老二
5.连续的子数组和 最大值
如:
1 2 3 -4 -6 7 5 -100 -99
6.数组部分和问题
假设有一个数组 a[N] N<=20
能不能从数组a中任选M个元素(M<=N),使的其和为K。
关键点:N<=20
任选
开灯:打开 1
关闭 0
x 0 1
x 0
x 0
x 0
x ==> 0
x 0
x 0
x 0
x 0
10ms
0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0
0 1 1 1 1 1 1 1 1 1 1 0
0 0 0 0 0 1 1 0 0 0 0 0
0 0 0 0 1 0 0 1 0 0 0 0 ===> 摇摇棒
0 0 0 1 0 0 0 0 1 0 0 0
0 0 1 0 0 0 0 0 0 1 0 0
0 1 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
010101010101010010101010101001010101
假设xxxx
0001
0011
0010
...
1111
是不是每一种可能都有了
遍历 遍历多少次 2^N-1 1<<N
for(i=0;i<(1<<N);i++)
{
....
}
每一次遍历:
1011
数组下标 0123
找出对应的数组的元素取出来加起来
判断二进制的最高位是否是1 sum+
判断二进制的最高位-1是否是1 sum+
1011
&
1000
>0 最高位为1
=0 最高位为0
i&(1<<j)=!0
sum+=a[j];
int sum;
int m;
for(i=0;i<(1<<N);i++)
{
sum=0;
//遍历每一位
m=0;
for(j=N-1;j>=0;j--)
{
if(i&(1<<j))
{
m++;
sum+=a[j];
}
}
if(m==M&&sum==K)
{
//
}
}
数组
最新推荐文章于 2024-08-22 18:03:40 发布