数组

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)
		{
			//
		}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值