——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
今天的内容让人迷糊,让人费解,让人晕乎乎,学的久了,也该换换脑子了,这几个排序也算是初级面试题吧,试试看,能不能分析明白。
最先讲的还是新的数据类型数组。
1. 数组基本概念
具有相同类型的若干变量有序的组织起来
属于构造数据类型,一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或构造类型
2.数组的几个名词
数组元素
数组的下标
数组元素的位置的一个索引或指示
数组的维数
数组下标的个数分为一维、二维、三维、多维
3. 分类
按元素不同:数值、字符、指针、结构、字符串
按维度分类:一维、二维、多维
一维数组
一个数组里存储的全是基本数据类型
类型说明符 数组名[常量表达式];
int s[n];
c语言中c99标准数组长度不可以为变量
而xcode可以:
int len = 5;
int a[len]; 这种情况是不可以初始化的
数组长度可以用宏定义:
#define宏定义
#define len 5
int a[len];
int a[3] = {1,23};
int a1[3] = {[1] = 23,[2] = 34};
int a2[3];
a2[0] = 1;
a2[1] = 2;
a2[2] = 3;
int len = 3;
int a3[len];//这种情况是不可以初始化的
a3[0] = 1;
a3[1] = 2;
a3[2] = 3;
注意:
1.如果定义时没有初始化,数组元素是有值的,是垃圾值
2.如果定义时进行了部分初始化,那么其他元素被系统自动初始化为0
3.字符型数组定义时如果部分初始化了,那么其他元素被系统自动初始化为0了,字符表示null
数组的存储方式:
1. 计算机会给数组分配一块连续的存储空间
2. 数组名代表数组的首地址,从首地址依次存入数组的第1、2、3、。。。个元素
3. 每个元素占用相同的字节数
4. 并且元素之间的地址是连续的
一维数组的地址:
// 定义两个数组,两个数组地址不一定连续。数组名代表了数组的首地址
// 数组内部各元素的地址是连续的int型数组内部元素之间相差4字节。
// 数组名创建了内容后,不允许再修改了
#include <stdio.h>
int main(int argc, const char * argv[]) {
int a[] = {1,2};
int b[5] = {3,4,5,6,7};
//先定义的数组分配在高地址
printf("a = %p\n",a);
printf("b = %p\n",b);
for (int i = 0; i < 5; i++) {
printf("&b[%d] = %p\n",i,&b[i]);
}
return 0;
}
数组传递地址注意
// 1.形参数组类型和长度要和实参一致
#include <stdio.h>
//这种写法可以:
//void print_arr(int arr[]){
// for (int i = 0; i < 5; i++) {
// printf("%d\t",arr[i]);
// }
//}
//int main(int argc, const char * argv[]) {
// int a[] = {1,2,3,4,5};
// print_arr(a);
// return 0;
//}
//这种写法错误1606416424 256 512 768 1024 这是下面的执行结果
//void print_arr(float arr[]){
// for (int i = 0; i < 5; i++) {
// printf("%d\t",arr[i]);
// }
//}
//int main(int argc, const char * argv[]) {
// int a[] = {1,2,3,4,5};
// print_arr(a);
// return 0;
//}
//关于数组名作为函数参数后,数组的长度信息丢失的问题
//C语言规定,不管什么类型的数据,数据的内存地址在内存中占用8字节。只要是地址
void print_arr2(int arr[]){//只传递过来首地址
int len = sizeof(arr);//不轮什么类型所有的地址都占8个字节
printf("arr2_len = %d\n",len);//8
}
//这种写法错误
// 地址传递是只传递名,不检查数组长度所以形参的数组长度可以与实参不一致,也可以不写数组长度
void print_arr(int arr[]){
for (int i = 0; i < 5; i++) {
printf("%d\t",arr[i]);
}
}
int main(int argc, const char * argv[]) {
int a[10] = {1,2,3,4,5,6,7,6,5,6};
int len = sizeof(a);
printf("a_len = %d\n",len);//40
print_arr(a);
print_arr2(a);
return 0;
}
数组中的越界问题
char s[2] = {‘c’,’h’};
下表范围:0、1
s[2]=‘s’//越界下标越界了
如果越界的内存空间是空的,其他数组占用此空间时,会覆盖这个空间,还会发生未知错误,系统崩溃。
#include <stdio.h>
int main(int argc, const char * argv[]) {
char s[2] = {'c','h'};//s[]数组下标范围是0-1
printf("%c\n",s[0]);
printf("%c\n",s[1]);
printf("%c\n",s[2]);//此时是越界的,不安全的,这个空间不属于s[]数组的
return 0;
}
数组元素作为函数参数
int a[4] = {1,2,3,4};
a[0]/a[1]/a[2]/a[3]就是数组元素
两种形式:
1. 把数组元素(下标变量)作为实参去使用
把作为实参的数组元素的值传递给形参,实现单向的值传递。
#include <stdio.h>
int sum(int x,int y){
return x+y;
}
int main(int argc, const char * argv[]) {
int a[5] = {1,2,3,4,5};
//需求:要求计算数组第一个元素a[0]和最后一个元素a[4]的和
//等同于传递了两个变量
printf("sum = %d\n",sum(a[0],a[4]));
return 0;
}
思考题1:
判别一个整数数组中各元素的值,若大于0则输出该值,若小于等于0则输出0.(判断过程用函数实现)
2. 把数组名作为函数的实参和形参去使用
要求形参和实参相应必须都是同类型数组
此时不是值传递,而是地址传递。
void change(int arr[2]){//相当于给a又起了个名字,没有新建内存空间
printf("&arr = %p\n",arr);
}
int main(int argc, const char * argv[]) {
int a[]={1,2};
change(a);//数组名a也是数组的首地址
printf("&a = %p\n",a);
return 0;
}
冒泡排序:Bubble Sort
重复比较,一次比较两个元素,如果顺序错误就把他们交换过来
大数下沉:每一次让最大的数跑到最后面去
小数上浮:每一次让最小的数跑到最前面
#include <stdio.h>
/*!
* @param arr 数组名
* @param len 数组长度
*/
void paiXu(int arr[],int len){
int temp;
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j+1]) {//重复比较,一次比较两个元素,如果顺序错误就把他们交换过来
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
for (int i = 0; i < 10; i++) {
printf("%d\t",arr[i]);
}
}
int main(int argc, const char * argv[]) {
int s[10] = {5,3,0,2,8,9,1,4,7,6};
paiXu(s,10);
return 0;
}
选择排序:
找到最小元素放到序列的起始位置,再找剩下的中最小的,依次摆放
#include <stdio.h>
void paiXu(int arr[],int len){
int temp;
for (int i = 0; i < len - 1; i++) {
for (int j = i + 1; j < len; j++) {//先同旁边的比较,一直比较到最后面一个数
if (arr[i] > arr[j]) {
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
for (int i = 0 ; i < 10; i++) {
printf("%d\t",arr[i]);
}
}
int main(int argc, const char * argv[]) {
int arr[10] = {10,4,23,8,97,2,3,1,8,-2};
paiXu(arr, 10);
return 0;
}
折半查找:
在有序表中,取中间元素作为比较对象,若给定值于中间元素的要查找数相等,则查找成功,值小于要查找的数,那么在中间左半区继续查找
若大于要查找的数,那么去右半区继续查找
// 折半查找效率最高
//条件是有序数组中查找
#include <stdio.h>
/*!
*
* @param arr 数组
@param len 数组长度
@param key 要查找的数
*
* @return 要查找的数的位置如果找不到返回-1
*
*/
int mid_Find(int a[],int len,int key){
int low = 0,mid,high = len-1;
while (low <= high) {
mid = (high + low) / 2;//数组中间位
if (key > a[mid]) {
low = mid + 1;//大于中间位的值则在右边区域找
}else if (key < a[mid])
high = mid - 1;//小于中间位的值则在左边区域找
else
return mid;
}
return -1;
}
int main(int argc, const char * argv[]) {
// int三个变量high、low、mid,当这三个变量在数组的同一位置时,取得这个值,若没有则提示没有这个数字
int arr[5] = {1,45,67,76,80};
// low mid high (high+low)/2 > num
// low high
int num = mid_Find(arr,5,4546);
if (num == -1) {
printf("查无次数\n");
}
printf("%d\n",arr[num]);
return 0;
}