C语言学习--排序和查找

提示:排序和查找算法是算法领域中最基本的概念之一,它们在数据组织、优化查询效率等方面发挥着至关重要的作用。

目录

前言

12.1 排序算法的介绍

12.2 冒泡排序

12.2.1 基本介绍

12.2.2 冒泡排序应用实例

12.2.3 分析冒泡的过程+代码

12.3 查找

12.3.1 介绍

12.3.2 案例演示

12.4 多维数组-二维数组

12.5 二维数组的应用场景

12.6 二维数组的使用

12.6.1 快速入门案例:

12.6.2 使用方式 1: 先定义在初始化

12.6.3 使用演示

12.6.4 使用方式 2: 直接初始化

12.7 二维数组的应用案例

12.7.1 案例 1

12.7.2 案例 2:

12.7.3 前面两个案例的代码

12.8 二维数组使用细节和注意事项

总结

附录


前言

在计算机科学中,算法是解决问题和执行任务的核心工具。排序和查找算法是算法领域中最基本的概念之一,它们在数据组织、优化查询效率等方面发挥着至关重要的作用。本章将深入探讨排序和查找算法的基本原理、实现方式以及它们的应用场景。同时,我们还将介绍二维数组的概念和使用,这是处理多维数据和构建复杂数据结构的基础。通过本章的学习,读者将能够理解并实现这些基本算法,为进一步探索更高级的算法和数据结构打下坚实的基础。


12.1 排序算法的介绍

排序也称排序算法(Sort Algorithm),排序是将一组数据,依指定的顺序进行排列的过程。

排序的分类:

1) 内部排序:

指将需要处理的所有数据都加载到内部存储器(内存)中进行排序。

2) 外部排序法:

数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。

12.2 冒泡排序

12.2.1 基本介绍

冒泡排序(Bubble Sorting)的基本思想是:通过对待排序序列从前向后(从下标较小的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就象水底下的气泡一样逐渐向上冒。

因为排序的过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行过交换,就说明序列有序,因此要在排序过程中设置一个标志 flag 判断元素是否进行过交换。从而减少不必要的比较。

12.2.2 冒泡排序应用实例

我们举一个具体的案例来说明冒泡法。我们将五个无序的数:{3, 9, -1, 10, -2} 使用冒泡排序法将其排成一个从小到大的有序数列。

12.2.3 分析冒泡的过程+代码

858fa8f16f2346cabfadf56242633d67.png

#include <stdio.h>

//冒泡排序的函数

void bubbleSort(int arr[], int arrLen) {

//因为每轮排序几乎一样,因此,我们可以使用 for 循环处理

int j,i;

int t;//临时变量

for(i=0; i < arrLen - 1; i++) {

for(j = 0; j < arrLen-1-i; j++) {

//如果前面的数大于后面的数,就交换

if(arr[j] > arr[j+1]) {

t = arr[j];

arr[j] = arr[j+1];

arr[j+1] = t;

}

}

}

}

void main() {

int arr[] = {3, 9, -1, 10, -2,-11} ;

int arrLen = sizeof(arr) / sizeof(int); // 通过计算得到

int j;

bubbleSort(arr, arrLen); // 数组默认是地址传递(指针)

printf("\n 排序后(函数)\n");  

for(j= 0; j < arrLen; j++) {

printf("%d ", arr[j]);

}

//第一轮的排序

/*

int j;

int t;//临时变量

for(j = 0; j < 4; j++) {

//如果前面的数大于后面的数,就交换

if(arr[j] > arr[j+1]) {

t = arr[j];

arr[j] = arr[j+1];

arr[j+1] = t;

}

}

//输出看看第 1 轮的排序后的情况

for(j= 0; j < 5; j++) {

printf("%d ", arr[j]);

}

//第 2 轮的排序

for(j = 0; j < 3; j++) {

//如果前面的数大于后面的数,就交换

if(arr[j] > arr[j+1]) {

t = arr[j];

arr[j] = arr[j+1];

arr[j+1] = t;

}

}

//输出看看第 2 轮的排序后的情况

printf("\n");

for(j= 0; j < 5; j++) {

printf("%d ", arr[j]);

}

//第 3 轮的排序

for(j = 0; j < 2; j++) {

//如果前面的数大于后面的数,就交换

if(arr[j] > arr[j+1]) {

t = arr[j];

arr[j] = arr[j+1];

arr[j+1] = t;

}

}

//输出看看第 3 轮的排序后的情况

printf("\n");

for(j= 0; j < 5; j++) {

printf("%d ", arr[j]);

}

//第 4 轮的排序

for(j = 0; j < 1; j++) {

//如果前面的数大于后面的数,就交换

if(arr[j] > arr[j+1]) {

t = arr[j];

arr[j] = arr[j+1];

arr[j+1] = t;

}

}

//输出看看第 3 轮的排序后的情况

printf("\n");

for(j= 0; j < 5; j++) {

printf("%d ", arr[j]);

}*/

getchar();

}

 

12.3 查找

12.3.1 介绍

在 C 中,我们常用的查找有两种:

1) 顺序查找

2) 二分查找

12.3.2 案例演示

1) 有一个数列:{23, 1, 34,89, 101}

猜数游戏:从键盘中任意输入一个数,判断数列中是否包含该数【顺序查找】 要求: 如果找到了,就提示找到,并给出下标值, 找不到提示 没有。

#include <stdio.h>

int seqSearch(int arr[], int arrLen, int val) {

int i;

for(i = 0; i < arrLen; i++) {

if(arr[i] == val) {

return i;

}

}

//如果在 for 循环中,没有执行到 return ,说明没有找到

return -1;

}

void main() {

//有一个数列:{23, 1, 34,89, 101}

//猜数游戏:从键盘中任意输入一个数,判断数列中是否包含该数【顺序查找】 要求: 如果找到了,

//就提示找到,并给出下标值, 找不到提示 没有。

//分析思路

//1. 安装数组进行遍历,一个一个的比较,如果相等,则找到

int arr[] = {23, 1, 34,89,101};

int arrLen = sizeof(arr) / sizeof(int);

int index = seqSearch(arr, arrLen, -101);

if (index != -1) { //找到

printf("找到 下标为 %d", index);

} else {

printf("没有找到");

}

getchar();

}

 

2) 请对一个有序数组进行二分查找 {1,8, 10, 89, 1000, 1234} ,输入一个数看看该数组是否存在此数,并且求出下标,如果没有就提示"没有这个数"。

二分查找的前提是,该数组是一个有序数组

#include <stdio.h>

//二分查找

int binarySearch(int arr[], int leftIndex, int rightIndex, int findVal) {

//先找到数组中间这个数 midVal

int midIndex = (leftIndex + rightIndex) / 2;

int midVal = arr[midIndex];

//如果 leftIndex > rightIndex, 说明这个数组都比较过,但是没有找到

if( leftIndex > rightIndex) {

return -1;//!!!!

}

//如果 midVal > findVal 说明, 应该在 midVal 的左边查找

if(midVal > findVal) {

binarySearch(arr, leftIndex, midIndex-1, findVal);//!!!

} else if(midVal < findVal){//如果 midVal < findVal 说明, 应该在 midVal 的右边查找

binarySearch(arr, midIndex+1, rightIndex, findVal);//!!!

} else {

return midIndex; //返回该数的下标

}

}

void main() {

//请对一个有序数组进行二分查找 {1,8, 10, 89, 1000, 1234} ,

//输入一个数看看该数组是否存在此数,并且求出下标,

//如果没有就提示"没有这个数"。

二分查找的前提是,该数组是一个有序数组

//思路分析

// 比如我们要查找的数是 findVal

//1. 先找到数组中间这个数 midVal,和 findVal 比较

//2. 如果 midVal > findVal 说明, 应该在 midVal 的左边查找

//3. 如果 midVal < findVal 说明, 应该在 midVal 的右边查找

//4. 如果 midVal == findVal, 说明找到

//5. 这里还有一个问题,没有考虑找不到情况->

int arr[] = {1,8, 10, 89, 1000, 1234};

int arrLen = sizeof(arr) / sizeof(int);

int index = binarySearch(arr, 0, arrLen-1, -1000);

if(index != -1) {

printf("找到 index = %d", index);

} else {

printf("没有找到");

}

getchar();

}

 

12.4 多维数组-二维数组

多维数组我们介绍二维数组

12.5 二维数组的应用场景

比如我们开发一个五子棋游戏,棋盘就是需要二维数组来表示。如图:

3bdb155f953544c09cdde8f1dccac3b4.png

12.6 二维数组的使用

12.6.1 快速入门案例:

请用二维数组输出如下图形

0 0 0 0 0 0

0 0 1 0 0 0

0 2 0 3 0 0

0 0 0 0 0 0

12.6.2 使用方式 1: 先定义在初始化

语法: 类型 数组名[大小][大小];

 

比如: int a[2][3];

12.6.3 使用演示

二维数组在内存的存在形式,各个元素的地址是连续分布的,即在前一个元素基础上+4

代码演示:

#include <stdio.h>

void main() {

//a[4][6] : 表示一个 4 行 6 列的二维数组

int a[4][6]; // 没有初始化,则是分配的内存垃圾值

int i, j;

//全部初始化 0

for(i = 0; i < 4; i++) { //先遍历行

for(j = 0; j < 6; j++) {//遍历列

a[i][j] = 0;

}

}

a[1][2] = 1;

a[2][1] = 2;

a[2][3] = 3;

//输出二维数组

for(i = 0; i < 4; i++) {

for(j = 0; j < 6; j++) {

printf("%d ", a[i][j]);

}

printf("\n");

}

看看二维数组的内存布局

printf("\n 二维数组 a 的首地址=%p", a);

printf("\n 二维数组 a[0]的地址=%p", a[0]);

printf("\n 二维数组 a[0][0]的地址=%p", &a[0][0]);

printf("\n 二维数组 a[0][1]的地址=%p", &a[0][1]);

//将二维数组的各个元素得地址输出

printf("\n");

for(i = 0; i < 4; i++) {

printf("a[%d]的地址=%p ", i, a[i]);

for(j=0; j < 6; j++) {

printf("a[%d][%d]的地址=%p ", i, j , &a[i][j]);

}

printf("\n");

}

getchar();

}

 

Ø 画出了二维数组的内存布局图!!!

1cfa4bd3d93d4fa1b4ec6426f0655c1a.png

12.6.4 使用方式 2: 直接初始化

1) 定义 类型 数组名[大小][大小] = {{值 1,值 2..},{值 1,值 2..},{值 1,值 2..}};

2) 或者 类型 数组名[大小][大小] = { 值 1,值 2,值 3,值 4,值 5,值 6 ..};

8bedd4689e914248a76c10dda9644b92.png

12.7 二维数组的应用案例

12.7.1 案例 1

请使用灵活的方式遍历如下数组 :

int map[3][3] = {{0,0,1},{1,1,1},{1,1,3}};

12.7.2 案例 2:

int arr[3][2]={{4,6},{1,4},{-2,8}};

遍历该二维数组,并得到和?

12.7.3 前面两个案例的代码

#include <stdio.h>

void main() {

int map[3][3] = {{0,0,1},{1,1,1},{1,1,3}};

//遍历

//先得到行

//1. sizeof(map) 得到这个 map 数组的大小 9 * 4 = 36

//2. sizeof(map[0]) 得到 map 中,第一行有多大 3 * 4 = 12

int rows = sizeof(map) / sizeof(map[0]); // 3

/*printf("rows=%d", rows);*/

//得到列

int cols = sizeof(map[0]) / sizeof(int); // 12 / 4 = 3

int i,j, sum=0;

for(i = 0; i < rows; i++) {

for(j = 0; j < cols; j++) {

printf("%d ", map[i][j]);

sum += map[i][j];//累计到 sum

}

printf("\n");

}

printf("\n sum=%d", sum);

getchar();

}

 

12.7.4 定义二维数组,用于保存三个班,每个班五名同学成绩,并求出每个班级平均分、以及所有班级平均分

#include <stdio.h>

void main() {

/*

定义二维数组,用于保存三个班,

每个班五名同学成绩,并求出每个班级平均分、以及所有班级平均分

分析

1. 创建一个 scores[3][5]

2. 遍历,给赋值

3. 再次遍历,统计总分和平均分

4. 输出

*/

double score[3][5]; //

int rows = sizeof(score) / sizeof(score[0]), cols = sizeof(score[0])/sizeof(double), i, j; //

//classTotalScore 各个班级总成绩 totalScore 所有学生成绩

double totalScore = 0.0, classTotalScore = 0.0;

for (i = 0; i < rows; i++ ) {

for (j = 0; j < cols ; j++ ) {

score[i][j] = 0.0; //初始化

}

}

//遍历,给每个学生输入成绩

for (i = 0; i < rows; i++ ) {

for (j = 0; j < cols ; j++ ) {

printf("请输入第 %d 个班的 第 %d 个 学生的成绩", i + 1, j + 1);

scanf("%lf", &score[i][j]);

}

}

//getchar();

//显示下成绩情况

for (i = 0; i < rows; i++ ) {

for (j = 0; j < cols ; j++ ) {

printf("%.2f ",score[i][j]);

}

printf("\n");

}

//统计各个班的总成绩,和所有学生的总成绩

for (i = 0; i < rows; i++ ) {

classTotalScore = 0.0; // 每次清 0

for (j = 0; j < cols ; j++ ) {

classTotalScore += score[i][j]; //累计每个班的总成绩

}

printf("\n 第 %d 个班的平均成绩是 %.2f" , i+1, classTotalScore/cols );

totalScore += classTotalScore; //将该班级的总分,累计到 totalScore

}

printf("\n 所有学生总成绩是 %.2f 平均成绩 %.2f" , totalScore, totalScore/(rows * cols));

getchar();

getchar();

}

 

12.8 二维数组使用细节和注意事项

1) 可以只对部分元素赋值,未赋值的元素自动取“零”值【案例】

int main(){

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

int i,j;

for (i = 0; i < 4; i++ ) {

for (j = 0; j < 5 ; j++ ) {

printf("%d ",a[i][j]);

}

printf("\n");

}

getchar();

}

 

2) 如果对全部元素赋值,那么第一维的长度可以不给出。比如:

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

可以写为:

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

3) 二维数组可以看作是由一维数组嵌套而成的;如果一个数组的每个元素又是一个数组,那么它就是二维数组。

二维数组 a[3][4]可看成三个一维数组,它们的数组名分别为 a[0]、a[1]、a[2]。

 

这三个一维数组都有 4 个元素,如,一维数组 a[0] 的元素为 a[0][0]、a[0][1]、a[0][2]、a[0][3]


总结

通过本章的学习,我们掌握了排序算法的基本概念,包括内部排序和外部排序的区别,以及冒泡排序的具体实现方法。我们了解了查找算法中的顺序查找和二分查找,并学习了它们在不同场景下的应用。此外,本章还详细介绍了二维数组的使用方法,包括定义、初始化、内存布局以及在实际问题中的应用案例。我们认识到了二维数组在实际编程中的重要性,以及如何通过二维数组解决多维数据处理问题。最后,我们总结了二维数组使用时的一些细节和注意事项,帮助读者在实际编程中避免常见错误,提高代码的准确性和效率。

附录

参考:【尚硅谷C语言零基础快速入门教程-哔哩哔哩】 https://b23.tv/vS3vTDp

 

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值