OutMan——C语言中的冒泡排序、选择排序、折半查找以及指针的介绍

本文介绍了C语言中的冒泡排序和选择排序算法,以及如何实现这两种排序方法。此外,还详细讲解了折半查找的概念和实现,包括折半查找和折半插入的代码示例。文章进一步探讨了指针的使用,包括一级和二级指针、指针数组、二维数组指针的定义和应用,以及如何使用指针处理二维字符数组。最后,文章讨论了字符串指针的注意事项和如何使用指针数组保存多个字符串。

冒泡排序

        冒泡排序:大数下沉,小数上浮

一、冒泡排序的代码实现
例:输入一组数据,使用冒泡排序法经行排序,并输出

void bubbleSort(int *array, int length)
{
    int temp;
    for (int i=0; i<length-1; i++)
    {
        for (int j=0; j<length-1-i; j++)
        {
            if (array[j] > array[j+1])
            {
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
    }
}

这里写图片描述

选择排序

一、选择排序的代码实现
例:输入一组数据,使用选择排序法经行排序,并输出

void selectSort(int *array, int length)
{
    int temp;
    for (int i=0; i<length-1; i++)
    {
        for (int j=i+1; j<length; j++)
        {
            if (array[i] > array[j])
            {
                temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
        }
    }
}

这里写图片描述

折半查找

        基本思路:在有序表中,可取中间元素作为比较对象,若给定值与中间元素(要查找的数)相等,则查找成功,若给定值小于中间元素(要查找的数),则在中间元素的左半区继续查找,若给定值大于中间元素(要查找的数),则在中间元素的右半区继续查找,不断重复上述查找过程,直到查找成功或所查找的区域无给定的数据元素,查找失败

一、折半查找代码实现
例:输入一组有序的数据,使用折半查找法查找一个数据,并输出其位置

int binSearch(int *array, int length, int key)
{
    int low = 0;
    int high = length - 1;
    int mid;
    // 循环
    while (low <= high)
    {
        // 计算mid的位置
        mid = (low + high)/2;
        if (key < array[mid])
        {
            high = mid - 1;
        }else if(key > array[mid])
        {
            low = mid + 1;
        }else
        {
            return mid;
        }
    }
    // 如果查找不到,通常返回-1
    return -1;
}

这里写图片描述

二、折半插入的代码实现
例:输入一组有序的数据,使用折半查找法插入一个数据,返回要插入数据的位置

int binSearch(int *array, int length, int key)
{
    int low = 0;
    int high = length - 1;
    int mid;
    while (low <= high)
    {
        mid = (low + high)/2;
        if (key < array[mid])
        {
            high = mid - 1;
        }else if(key > array[mid])
        {
            low = mid + 1;
        }else
        {
            return mid + 1;
        }
    }
    return low;
}

这里写图片描述

指针

一、使用指针的好处
1. 为函数提供修改调用变量的灵活手段
2. 让函数有多个返回值
3. 可以改善某些子程序的效率
        在数据传递时,如果数据块较大(比如说数据缓冲区或比较大的结构),这时就可以使用指针传递地址而不是实际数据,既提高传输速度,又节省大量内存

二、变量的存取方式
1. 直接存取
2. 间接存取

三、指针及指针变量的概念
指针变量:用来存放地址的变量,也可以说用来存放指针的变量
指针:是一个地址,是一个常量

四、指针定义的注意事项
        指针变量归根结底还是变量,也有全局和局部变量之分

五、野指针
        指针变量如果不进行初始化,里面会有一个垃圾直,这时候我们称这是个野指针,如果操作一个野指针:
1. 可能会导致程序崩溃
2. 可能会访问了不该访问的数据
所以:指针变量必须初始化才可以使用

六、应用:逆序数组
        设计要求:用指针将数组a中的n个整数按相反顺序存放
        解决办法:将a[0]和a[length-1]交换位置,a[1]和a[length-1-1]交换位置……

void niXuArray(int *array, int length)
{
    int l = 0;
    int h = length - 1;
    int temp;
    while (l < h)
    {
        temp = array[l];
        array[l] = array[h];
        array[h] = temp;
        l++;
        h--;
    }
}

这里写图片描述

二级指针

一、介绍
        如果一个指针变量存放的是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量,也称为二级指针

int a = 1;
int *p = &a;
// 二级指针
int **p2 = &p;
// 三级指针
int ***p3 = &p2;
// 四级指针
int ****p4 = &p3;

//如果想要修改a中的值
// 方式一
a = 10;
// 方式二
*p = 10;
// 方式三
**p2 = 10;
// 方式四
***p3 = 10;
// 方式五
****p4 = 10;

一维指针数组

一、概念
        指针数组:一个数组的元素值为指针(存放指针或地址的数组)
        指针数组格式:
        类型说明符 *数组名[元素个数];
其中:类型说明符为指针值所指向的变量类型
例:int *pa[3];
表示pa是个指针数组,它有3个数组元素,每个元素值都是一个指针,指向整型变量

二、指针数组的使用

int a = 3;
int b = 4;
int c = 5;

int *pa[3] = {&a, &b, &c};
// 访问a的值
printf("%d\n", *pa[0]);
// 使用数组名来访问a的值
printf("%d\n", **pa);

延伸的知识点:
这里写图片描述
分析:
p == &a1[0]
*p == a1[0]
**p == *a1== 1
数组名就是数组的地址,也是数组首元素的地址

指针变量间的运算

一、两个指针变量之间的减法运算:
        两个指针变量相减所得之差是两个指针所指数组元素之间相差的元素个数(实际上是两个指针值(地址)相减之差再除以指向的类型所占用的字节)
常见用法:两个指针都指向同一个数组
(1)判断两个指针变量指向的元素是否连续
(2)判断两个指针变量指向的元素之间相隔几个元素
这里写图片描述
注意:两个指针变量之间没有加法运算
总结:
(1)如果两个指针变量,指向数组同一个元素,那么它们相减的结果是0
(2)如果两个指针变量,指向同一个数组中相邻的两个元素,那么它们相减的结果是1或者-1

二、指针变量之间的关系运算

int a[] = {1, 2, 3, 4, 5, 6, 7};
int *p = a;
int *p2 = &a[5];
printf("%d", p>p2);

如果结果为1(真),说明p在高位,p2在低位
如果结果为0(假),说明p在低位,p2在高位
这里写图片描述

用数组名访问二维数组元素

这里写图片描述

二维数组指针的定义、初始化

        二维数组名是指向行的,它不能对如下说明的指针变量p直接赋值

int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
// 这是有问题的(有警告)
int *p = a;

        其原因就是p与a的对象性质不同,或者说二者不是同一级指针,C语言通过定义行数组指针的方法,是的一个指针变量与二维数组名具有相同的性质
        格式:
        数据类型 (*指针变量名)[二维数组列数];
数据类型:为所指数组的数据类型
*:表示其后的变量是指针类型
如果要将二维数组赋给指针,应该这样赋值:

int a[3][4];
// 该语句是定义一个数组指针,指向含4个元素的一位数组   
int (*p)[4];
// 将二维数组的首地址赋给p,也就是a[0]或&a[0][0]   
p = a;
// 下面语句执行过后,也就是p = p + 1;
// p跨过了a[0][]指向了a[1][]
// 所以数组指针也称为指向一维数组的指针,亦称行指针
p++;

一、数组指针
        定义一个指针变量,让这个指针指向一维数组的元素

二、二维数组指针
        行指针,用来指向二维数组的每一行,存放的是行的首地址
三、二维数组指针的定义格式
        数据类型 (*行指针变量名)[数组第二维的长度];
四、二维数组的初始化

int a[3][4];
int (*p)[4] = a;

五、二维数组指针的使用
使用二维数组指针遍历二维数组
(1)p[i][j]
这里写图片描述
(2)*(p[i]+j)
这里写图片描述
(3)*(*(p+i)+j)
这里写图片描述

六、指针数组和二维数组指针的区别
1. 指针数组

int *p[3];

p表示一个指针数组,p[0]、p[1]和p[2]均为指针变量
2. 二维数组指针

int (*p)[3];

p表示一个指向二维数组的指针变量,该二维数组的列数为3或分解为一维数组的长度为3

字符串指针

一、基本介绍

// "believe"这个字符串存储在常量区
// str只保存了字符串常量的首地址
char *str = "believe";
printf("%s\n", str);
// 指针变量都是占用8个字节
int s = sizeof(str);
printf("%d\n", s);

注意:
1. 使用字符数组来保存的字符串是保存在栈里面的,保存在栈里面的东西是可读可写,所以我们可以改变里面的字符
2. 使用指针来保存的字符串,它保存的是字符串常量地址,常量区是只读的,所以我们不可以修改字符串中的内容

二、利用指针遍历字符串
这里写图片描述

三、使用注意
(1)错误写法

// 错误写法
char *str;
scanf("%s", str);

分析:str没有初始化,是个野指针
(2)错误写法

// 错误写法
char *str1 = NULL;
scanf("%s", str1);

分析:str1这个指针没有分配存储单元,没有地方去存储用户输入的字符串,所以会报错
(3)破法1

char *str = NULL;
// 这句话作用:先申请了100个字节的内存给str1
// str1就指向了这100个字节内存的首地址
str = malloc(100);
scanf("%s", str);

(4)破法2

char str[100];
// 字符指针str2指向了字符数组str的首地址
char *str2 = str;
scanf("%s", str2);

二维字符数组

一、一维字符数组

char str[100];
// 字符指针str2指向了字符数组str的首地址
char *str2 = str;
scanf("%s", str2);

// 一维字符数组
char ch[] = {'a', 'b', 'c'};
char ch2[] = "abc";

二、二维字符数组

// 二维字符数组
char ch[2][4] = {
    {'a', 'b', 'c', 'd'},
    {'d', 'e', 'f', 'h'},
};

三、利用二维数组保存多个字符串

// 利用二维字符数组保存多个字符串
char ch[2][4] = {"abc", "bcd"};

其中:
1. 第一维存的是每个字符串的首地址
2. 第二维存的是每个字符串的最大长度

四、利用指针数组保存多个字符串

// 利用指针数组保存多个字符串
char *name[3] = {"rose", "jim", "jack"};

其中:3指的是数组中最多能存放多少个元素,而不是指数组中字符串的长度

五、char类型指针数组和字符数组
(1)char类型指针数组
这里写图片描述
(2)char类型指针变量与字符数组

// 字符串指针
char *str = "abc";
// 字符数组
char str2[] = "abc";

// str是一个字符串指针,指向可以改变
str = "hello";
// str2 是一个数组名,是一个常量,不能被赋值
// str2 = "hello"; // 错误写法

六、应用:字符串排序
        设计要求:将5个国家名按字母顺序排列后输出
(1)使用冒泡排序法进行排序

void bubbleSort(char *array[], int length)
{
    char *temp;
    for (int i=0; i<length-1; i++)
    {
        for (int j=0; j<length-1-i; j++)
        {
            if (strcmp(array[j], array[j+1])>0)
            {
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
    }
}

这里写图片描述

(2)使用选择排序法进行排序

void selectSort(char *array[], int length)
{
    char *temp;
    for (int i=0; i<length-1; i++)
    {
        for (int j=i+1; j<length; j++)
        {
            if (strcmp(array[i], array[j])>0)
            {
                temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
        }
    }
}

这里写图片描述


                                        —— 如果您有不同的见解,请随时指出,期待与您的交流!——


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值