C语言学习笔记(5)之数组

数组

1. 问题的引入
int a;//定义一个整型

int a1,a2,a3,…a99;
有没有一种办法可以一次性的定义一组相同类型的变量?
数组。

2. 数组
一组具有相同类型的数组元素的有序集合。
在C语言中:
一维数组
二维数组
三维数组
。。。。
但是实际上我们的C语言中只有一维数组。

3. 一维数组

(1) 定义格式
类型说明符 数组名[整型表达式] {={初始值列表}};

“类型说明符”:指定数组中元素的类型,而不是数组的类型!
可以是C语言中任意合法的类型。

“数组名”:数组的名字。“标识符”

“整型表达式”:指定数组中元素的个数的。
C语言规定,在定义数组时,需要指定数组元素的个数,“常量表达式”。

例子:
int a[10];//定义了一个数组,数组名为a,里面包含了10个int类型的元素。
int是数组元素的类型,不是数组a的类型。
	typeof(4) <==>  int 
	typeof(a) <==> int [10]

求一个对象的类型小技巧:
获取到这个对象的完整的定义,然后把对象的名字从定义中去除,剩下的就是
这个对象的类型。

一维数组在内存中的存放:
在连续的地址空间中,从低地址到高地址依次连续存放数组中的每一个元素。

(2) 一维数组中元素的引用(访问)
char a[5];
引用数组元素的方法:
数组名[下标]

下标:C语言约定数组元素的下标是从0开始的。

引用数组元素和引用普通变量是一样的。
数组元素也有左值和右值的。

a[0] = 'A';
a[0]代表的是某一块内存空间(左值)

char b = a[0];
a[0]代表是某一块内存空间中的值(右值)

(3) 一维数组的初始化
初始化是指:定义对象时,就指定对象的值。

数组的初始化是用{}

  1. 全部初始化
    int a[10] = {0,1,2,3,4,5,6,7,8,9};

  2. 可以对部分元素进行初始化,后面的元素自动初始化为0
    int a[10] = {1,2,3};
    int a[10] = {0};

  3. 如果对全部数组元素进行初始化,那就可以不指定数组的长度
    int a[] = {0,1,2,3,4};

    注意:
    int a[10];
    a[10] = {0,1,2,3,4,5,6,7,8,9};//error
    a = {0,1,2,3,4,5,6,7,8,9};//error

    printf("%d\n",a);

    char c[10];
    printf("%c\n",c);

    练习:

    1. 定义一个5个整型元素的数组,并通过键盘获取这5个元素的值,然后打印到终端的。

    2. 定义一个int类型数组,从键盘上获取值,求该数组中各元素之和、元素最大值以及元素
      的最小值。

    3. 判断一个一维数组a[5]是否为递增
      a[0] <= a[1] <= a[2] <= a[3] <= a[4]
      a[0] <= a[1] && a[1] <= a[2] && … && a[3] <= a[4]

      if(a[i] > a[i+1])
      {
      	printf("不是递增");
      }
      
    4. 把每一个元素按一定的规则放置到合适的位置上去。
      对一个数组进行排序。
      冒泡法:
      相邻的两个元素,两两进行比较,把较大者往后移(两两交换)

      	int a[10];
      		//第一轮
      		if(a[0] > a[1])
      		{
      			a[0] <===> a[1]//互换
      		}
      		
      		if(a[1] > a[2])
      		{
      			a[1] <===> a[2]
      		}
      		
      		....
      		
      		if(a[n - 2] > a[n - 1])
      		{
      			a[n-2] <===> a[n-1]
      		}
      		
      		//第一轮
      		int i;
      		int temp;
      		for(i = 0;i < 9;i++)
      		{
      			if(a[i] > a[i+1])
      			{
      				temp = a[i];
      				a[i] = a[i+1];
      				a[i+1] = temp;
      			}
      		}
      		
      		//第二轮
      		if(a[0] > a[1])
      		{
      			a[0] <===> a[1]//互换
      		}
      		
      		if(a[1] > a[2])
      		{
      			a[1] <===> a[2]
      		}
      		
      		....
      		
      		if(a[n - 3] > a[n - 2])
      		{
      			a[n-2] <===> a[n-1]
      		}
      		
      		//第二轮
      		int i;
      		int temp;
      		for(i = 0;i < 8;i++)
      		{
      			if(a[i] > a[i+1])
      			{
      				temp = a[i];
      				a[i] = a[i+1];
      				a[i+1] = temp;
      			}
      		}
      		
      		//第三轮
      		.....
      	
      		//总结:
      		int i,n;
      		int temp;
      		for(n = 9;n >= 1;n--)
      		{
      			for(i = 0;i < n;i++)
      			{
      				if(a[i] > a[i+1])
      				{
      					temp = a[i];
      					a[i] = a[i+1];
      					a[i+1] = temp;
      				}
      			}
      		}
      

      选择法:
      1. 选择一个最大的元素
      2. 把最大的元素与最后一个元素进行位置互换

      	//第一轮
      	int a[5],temp;
      	int i,i_max = 0;
      	int max = a[0];
      	for(i = 0;i < 5;i++)
      	{
      		if(a[i] > max)
      		{
      			max = a[i];//记录数组中的最大值
      			i_max = i;//记录数组中最大值元素的下标
      		}
      	}
      	
      	if(i_max != 4)
      	{
      		temp = a[4];
      		a[4] = a[i_max];
      		a[i_max] = temp;
      	}
      	
      	
      	//第二轮
      	int i,i_max = 0;
      	int max = a[0];
      	for(i = 0;i < 4;i++)
      	{
      		if(a[i] > max)
      		{
      			max = a[i];//记录数组中的最大值
      			i_max = i;//记录数组中最大值元素的下标
      		}
      	}
      	
      	if(i_max != 3)
      	{
      		temp = a[3];
      		a[3] = a[i_max];
      		a[i_max] = temp;
      	}
      	
      	//第三轮
      	...
      	
      	//总结:
      	int n;
      	for(n = 5;n >= 2;n--)
      	{
      		int i,i_max = 0;
      		int max = a[0];
      		for(i = 0;i < n;i++)
      		{
      			if(a[i] > max)
      			{
      				max = a[i];//记录数组中的最大值
      				i_max = i;//记录数组中最大值元素的下标
      			}
      		}
      		
      		if(i_max != n - 1)
      		{
      			temp = a[n - 1];
      			a[n - 1] = a[i_max];
      			a[i_max] = temp;
      		}
      	}
      
      
      ....
      
      1. 求斐波拉契数列的前二十项之和。
        1 1 2 3 5 8 13…

      2. 不用排序,把一个数组中的负数放在数组的前面。

        8 -1 5 -6 7 9 -3

      3. 求一个一维数组中的第二大的元素,不用排序。

        //跟着老大走,你就是老二

      4. (选做)
        假设有一个数组a[n],能不能从数组a中任选m个元素(m <= n),使其和为k
        n = 10,m = 5,k = 10
        int a[10] = {-1,6,7,-5,3,2,-4,1,10,-8};

        穷举:把所有的子数组全部都找出来进行判断:
        1. 子序列的个数要为m个。
        2. 子序列中的元素的和必须为k。

        int a[2] = {1,2};
        {}
        {1}
        {2}
        {1,2}
        共有4种子数组

        int a[3] = {1,2,3};
        {}
        {1} {2} {3}
        {1,2} {1,3} {2,3}
        {1,2,3}
        共有8种子数组


        推论:
        int a[n]一共有2^n种子数组。

        int a[5] = {1,2,3,4,5};
        22222

        int a[2] = {1,2};
        a[1] a[0]
        i = 0 0 0 {}
        i = 1 0 1 {1}
        i = 2 1 0 {2}
        i = 3 1 1 {1,2}

        int a[3] = {1,2,3};
        a[2] a[1] a[0]
        i = 0 0 0 0 {}
        i = 1 0 0 1 {1}
        i = 2 0 1 0 {2}
        i = 3 0 1 1 {1,2}
        i = 4 1 0 0 {3}
        i = 5 1 0 1 {1,3}
        i = 6 1 1 0 {2,3}
        i = 7 1 1 1 {1,2,3}

        //i的第xbit为1代表选中了a[x],为0代表没有选中
        
        //遍历所有的子数组
        for(i = 0;i < (1 << sizeof(a)/sizeof(int));i++)
        {
        	//i表示的第几种子数组
        	int sum = 0;//子数组中各元素之和
        	int num = 0;//子数组中各元素的个数
        	//遍历i的低sizeof(a)/sizeof(int)个bit
        	for(x = 0;x < sizeof(a)/sizeof(int);x++)
        	{
        		if(i & (1 << x))//判断i的第xbit是否为1
        		{
        			//i = 5  a[0] + a[2]
        			//101		i
        			//001		1 << x(x == 0)
        			//001		代表选中了a[0]
        			//101		i
        			//010		1 << x(x == 1)
        			//000		代表没有选中a[1]
        			//101		i
        			//100		1 << x(x == 2)
        			//100		代表选中了a[2]
        			sum += a[x];
        			num++;
        		}
        	}
        	
        	if(num == m && sum == k)
        	{
        		//第i种子数组满足要求
        		//将第i中子数组打印出来即可
        	}
        }
        
  4. 查找一个元素
    对于数组常用的操作:
    增、删、改、查

    增:假设有一个有序数组a,这个数组足够大,现在需要将一个从键盘上输入的整型
    插入到这个数组中去,并且还要保证这个数组的有序性。

    删:略
    改:略

    查:在一个递增数组a[n]中查找一个值为x的元素,如果找到了则返回这个元素的下标
    如果没有找到则返回-1.

    (1)	遍历查找法
    	int i;
    	for(i = 0;i < n;i++)
    	{
    		if(a[i] == x)
    		{
    			return i;
    		}
    	}
    	return -1;
    	low逼法。
    
    (2)	折半查找法
    

    练习:

     	求出一个数组中连续的子数组之和中的最大值。
    	
    	穷举法:
    		把所有的连续的子数组全部列举出来,然后求累加和,最后比较
    	
    		以a[0]开头的子数组:
    			a[0]
    			a[0] a[1]
    			a[0] a[1] a[2]
    			......
    			a[0] a[1] a[2] ... a[9]
    		
    			int max = a[0];
    			
    			int sum = 0;
    			for(i = 0;i < sizeof(a)/sizeof(int);i++)
    			{
    				sum += a[i];
    				if(sum > max)
    				{
    					max = sum;
    				}
    			}
    
    		以a[1]开头的子数组:
    			a[1]
    			a[1] a[2]
    			a[1] a[2] a[3]
    			......
    			a[1] a[2] a[3] ... a[9]
    
    			int sum = 0;
    			for(i = 1;i < sizeof(a)/sizeof(int);i++)
    			{
    				sum += a[i];
    				if(sum > max)
    				{
    					max = sum;
    				}
    			}
    
    		int max = a[0];
    		for(j = 0;j < sizeof(a)/sizeof(int);j++)
    		{
    			int sum = 0;
    			for(i = j;i < sizeof(a)/sizeof(int);i++)
    			{
    				sum += a[i];
    				if(sum > max)
    				{
    					max = sum;
    				}
    			}
    		}
    
  5. 二维数组
    int a[4];
    定义了一个一维数组,数组名为a,数组a中一共有4个int类型的元素,分别是a[0] a[1] a[2]
    a[3]。
    我们在定义数组a的同时,也声明了一个新的类型,“像a这样的类型”。

    typeof(a) —> int [4]//a的类型

    我们如果想定义3个a这样的类型,该怎么定义?

    类型说明符 数组名[整型表达式] {={初始值列表}};

    int [4] b[3];//定义了一个数组,数组名为b,里面包含了3个int [4]这种类型的元素。
    ====>int b[3][4];//二维数组

    int [4] b[3]; ====>int b[3][4];//二维数组
    定义了一个数组b,里面含有三个元素:
    b[0] 里面又包含了4个int,b[0]又是一个数组,数组名为b[0]
    b[1] 里面又包含了4个int,b[1]又是一个数组,数组名为b[1]
    b[2] 里面又包含了4个int,b[2]又是一个数组,数组名为b[2]

    总结:C语言中,二维数组实际上就是一维数组,只不过该一维数组中的每一个元素又是
    一个一维数组。

    但是,为了便于理解,我们将int b[3][4]理解为一个3行4列的矩阵。

    二维数组的定义:
    类型说明符 数组名[整型表达式][整型表达式] {={初始值列表}};
    代表多少行 代表多少列

    二维数组在内存中的存放:
    按行存放,即先顺序存放第一行的元素,再存放第二行的元素。。。。。

    二维数组的引用:
    数组名[第几行][第几列]

    引用二维数组的元素和引用普通变量的方式是一模一样的。
    也会有左值和右值之分。
    
    a[0][2] = 2;
    int b = a[0][2];
    

    二维数组的初始化:
    (1) 分行给二维数组赋初值

    int b[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
    

    (2) 将所有数组全部写在一个花括号内,按数组的排序顺序对各元素进行初始化。

    int b[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
    

    (3) 对部分元素赋初值,其余的元素自动初始化为0

    		int b[3][4] = {1,2,3,4};
    		int b[3][4] = {{1},{2},{3,4}};
    

    (4) 如果对全部元素都赋初值,则定义数组时可以对第一维的长度省略,
    但第二维的长度不能省略。

    int b[][4] = {1,2,3,4,5,6,7,8,9,10};
    
    int b[3][4];
    b[3][4] = {1,2,3,4,5,6,7,8,9,10};//error
    b = {1,2,3,4,5,6,7,8,9,10};//error
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值