数组(冒泡排序)

目录

>一维数组

·数组的创建和初始化

·一维数组的使用

·一维数组在内存中的存储

>二维数组

·二维数组的创建和初始化

·二维数组的使用 

 ·二维数组在内存中存储 

>数组越界

>数组作为函数参数

·数组名的理解

​编辑

·冒泡排序


数组是一组相同类型元素的集合。

>一维数组

·数组的创建和初始化

数组的创建和初始化实例:


	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };//完全初始化
	int arr2[10] = { 1,2,3,4,5 };//不完全初始化,剩余元素默认都是0
	int arr3[10] = { 0 };//不完全初始化,剩余元素默认都是0
	int arr4[] = { 0 };//省略数组的大小,数组必须初始化,数组的大小是根据数组的内容来确定的
	int arr5[] = { 1,2,3 };

	char arr6[] = "abc";//此数组有四个元素还有一个\0
	char arr7[] = { 'a','b','c' };//此数组有三个元素
	char arr8[] = { 'a',98,'c' };//也可以将b换成b的ASCLL码值,结果是一样的

C99标准之前,数组的大小只能是常量表达式,C99标准中引入了变长数组的概念,使得数组在创建的时候可以使用变量,但是这样的数组不能初始化。

·一维数组的使用

数组是使用下标来访问的。数组的大小可以通过计算得到。

实现数组的输入与输出:

    arr1[5];//[]下表引用操作符,找到了6,数组元素下表从0开始
	int size = sizeof(arr1) / sizeof(arr1[1]);//整个数组大小除以一个元素的大小即为数组的个数,sizeof求出来的是字节数,以arr1为例,算出数组的总大小为10*4=40个字节,因为是整型                            数组,一个整型是4个字节
	for (i = 0; i < size; i++)
	{
		scanf("%d", &arr1[i]);
	}
	for (i = 0; i < size; i++)
	{
		printf("%d ", arr1[i]);//即可打印arr1中所有的元素,访问元素的时候可以用变量
	}

·一维数组在内存中的存储

探讨数组在内存中的存储,可以打印每个元素的地址来观察

int arr[10] = { 1,2,3,4,5 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("&arr[%d] = %p\n", i, &arr[i]);//%p用来打印地址,
	}

代码运行结果如下:

 

 C在16进制中就是12,可见每个地址相差4,逢16进1,每一个元素占四个字节。

一维数组在内存中是连续存放的,随着数组下标的增长,元素的地址,也在有规律的递增,由低地址到高地址

>二维数组

·二维数组的创建和初始化

一维数组已经不能满足更多数据的存放,二维数组有行有列。

    int arr[3][4];//3行4列的数组
	int ch[4][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7},{5,6,7,8,9} };//二维数组的初始化
	int ch1[4][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7,5,6,7,8,9 };//还可以这样初始化,结果相同,一行放满再放下一行,没放满的自动补零
	int ch2[4][5] = { {1,2,3},{4,5,2,3,4},{5,6,3,4},{5,6,7,5,6} };//不完全初始化可以用括号括起来来决定一行立面放几个元素

	printf("%d", ch2[1]);//格式符冲突

	int ch1[][4] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7,5,6,7,8,9 };//数组的行可以省但是列不能省,

·二维数组的使用 

二维数组是如何访问的呢?

    int arr2[4][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7},{4,5,6,7,8} };
	printf("%d", arr2[2][3]);//指定具体的元素即可用%d来打印,二维数组的下标依旧是从零开始

如果想打印每一个元素,则需要两层循环嵌套。

    int i = 0;
	int j = 0;
	for (i = 0; i < 4; i++)
	{
		for (j = 0; j < 5; j++)
		{
			printf("%d ", arr2[i][j]);
		}

		printf("\n");//将换行符放到行循环中
	}

 ·二维数组在内存中存储 

 我们依然打印每个元素的地址

    for (i = 0; i < 4; i++)
	{
		for (j = 0; j < 5; j++)
		{
			printf("arr2[%d][%d] = %p\n", i, j, &arr2[i][j]);
		}

		printf("\n");//将换行符放到行循环中
	}

结果如下

 一行内部每个元素的地址差四,说明一行内部的每个元素是连续的,每一行的最后一个元素和下一行的第一个元素也是连续的

>数组越界

有时候编译器并不会报错,需要自己检查是否有数组越界现象,一维数组与二维数组均可能出现越界访问现象

>数组作为函数参数

·数组名的理解

数组名通常情况下都是数组首元素的地址

int main()
{
	int arr[10] = { 1,2,3,4,5,6 };
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);

	return 0;
}

也有例外的情况

printf("%d\n", sizeof(arr)); 

这个结果打印出来40,为什么不是4或者8呢?

sizeof(数组名),数组名单独放在sizeof()内部,这里的数组名表示的是整个数组,计算的是整个数组的大小 

第二个例外是&数组名,这里的数组名也表示整个数组,这里取出的是整个数组的地址,除此之外均表示首元素的地址

注意:数组的地址其实就是数组首元素的地址

    printf("%p\n", arr);//表示的是数组首元素的地址
	printf("%p\n", &arr[0]);//表示的是数组首元素的地址
	printf("%p\n", &arr);//表示的是整个数组的地址,其实也是首元素的地址

	printf("%p\n", arr+1);
	printf("%p\n", &arr[0] + 1);
	printf("%p\n", &arr+1);

 得出的结果前两种均是首元素地址加1,而第三种加了40,因为第三种是整个数组地址加1,整个数组占40个字节

·冒泡排序

两两元素相邻进行比较

每经历一次冒泡排序,就可以排出一个元素,假如有n个元素,则要进行n-1次排序,每一次内部又要进行n-1次两两比较

先要确定外部的次数,在确定内部的次数

//冒泡排序——两两相邻元素进行比较
int i = 0;

for (i = 0; i < sz - 1; i++)//确定外部次数
{
	int j = 0;
	for (j = 0; j < sz - 1 - i; j++)//确定内部次数
	{
		if (arr[j] > arr[j + 1])
		{
			int tmp = arr[j];
			arr[j] = arr[j + 1];
			arr[j + 1] = tmp;
		}
	}
}

如何把冒泡排序封装成一个函数,如何把数组传参

arr作为数组传参的时候,数组传参传递的是首元素地址,因此形参的部分其实·也是一个指针变量,为了避免后续求数组大小的时候求的是数组指针的大小,我们传参数时,将数组的大小(在main函数中先行计算)也作为参数传递过去

void bubble_sort(int arr[10],int sz)
{
	int i = 0;
	for (i = 0; i < sz - 1; i++)//确定外部次数
			{
				int j = 0;
				for (j = 0; j < sz - 1 - i; j++)
				{
					if (arr[j] > arr[j + 1])
					{
						int tmp = arr[j];
						arr[j] = arr[j + 1];
						arr[j + 1] = tmp;
					}
				}
			}
	

int main()
{
	int arr[10] = { 0 };
	
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; i++)
	{
		scanf("%d", &arr[i]);
	}


	//排序的方法:冒泡排序,选择排序,插入排序,快速排序

	bubble_sort(arr,sz);//数组传参的时候只写数组名,不传数组的具体元素

	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}




	return 0;
}

数组传参要注意需要传递数组的大小参数

此处并不是指形参数组方括号中的大小,在C/C++语言中,数组作为函数形参时,可以不写数组大小。这是因为在函数形参中,数组被隐式转换为指针类型,当数组作为函数形参时,实际上传递给函数的是数组的首地址,而不是整个数组,所以写与不写都是一样的。

既然数组传递过去的是指针,我们不妨直接将形式参数变为指针变量,即int* arr

冒泡排序如何优化呢?

每一次冒泡排序前,假设已经有序了,当我们没有发生交换时,则证明冒泡排序已经有序了

    for (i = 0; i < sz - 1; i++)//确定外部次数
			{
				int j = 0;
				int flag = 1;
				for (j = 0; j < sz - 1 - i; j++)
				{
					if (arr[j] > arr[j + 1])
					{
						int tmp = arr[j];
						arr[j] = arr[j + 1];
						arr[j + 1] = tmp;
						flag = 0;
					}
				}

				if (flag == 1)
					break;
			}

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值