首页 > 其他分享 >C语言学习--排序和查找

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

时间:2024-08-19 12:55:38浏览次数:14  
标签:arr -- ++ C语言 int 二维 查找 数组 printf

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

目录

前言

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

 

标签:arr,--,++,C语言,int,二维,查找,数组,printf
From: https://blog.csdn.net/weixin_62881069/article/details/141263442

相关文章

  • C语言学习--断点调试
    提示:断点调试作为一种重要的调试技术,能够帮助程序员逐行分析代码的执行过程,查找潜在的Bug,并最终解决问题。目录前言13.1一个实际需求13.2断点调试介绍13.3断点调试的快捷键13.4断点调试应用案例113.5断点调试应用案例213.6断点调试应用案例313.7断点调试......
  • Linux下的库(静态与动态)原理与制作
    程序的编译过程程序的编译过程是将源代码转换为可执行文件的一系列步骤。这个过程通常包括预处理、编译、汇编和链接等阶段 1.预处理(Preprocessing)预处理器(cpp)处理源代码文件中的预处理指令,如#include和#define。它展开宏定义,包含头文件,并删除注释。输出是经过预处理的......
  • Redis的十大数据类型的常用命令(上)
    目录1.key的操作命令2.String的常用命令案例一:dy点赞案例二:文章的喜欢数3.List的常用命令案例:公众号订阅的消息4.Hash的常用命令案例:早期购物车设计5.Set的常用命令案例一:抽奖小程序案例二:朋友圈点赞案例三:朋友圈点赞6.Zset的常用集合(sortedset)案例一:根据商品......
  • 威高血净偏高的关联交易:销售费用率远高同行,现金流转负
    《港湾商业观察》施子夫 王璐日前,山东威高血液净化制品股份有限公司(以下简称,威高血净)针对首轮审核问询函进行了回复。威高血净的上市梦由来已久。早在2022年6月公司就递表港交所,其后无果,2023年12月30日公司又递表上交所主板,保荐机构为华泰联合证券。威高血净成立于2004......
  • 中创新航再被宁德时代专利诉讼不止不休,遭机构下调评级和目标价
    《港湾商业观察》黄懿7月26日,中创新航科技集团股份有限公司(下称“中创新航”,03931.HK)发布《诉讼公告》,将其与宁德时代新能源科技股份有限公司(下称“宁德时代”,300750.SZ)的专利诉讼再次推进大众视线中。业绩上来看,中创新航2023其增收不增利的欠佳表现遭到机构下调评级和目标......
  • Leetcode-552 学生出勤记录II
    Leetcode-552学生出勤记录II1.题目描述2.解题思路3.代码实现1.题目描述Leetcode-552学生出勤记录II2.解题思路(1)使用记忆化搜索来实现;(2)定义f[i][j][k]为右边填写j个A,且右边相邻位置有k个连续的L的情况下,向左填字母能构造多少个长为i的字符串;(3)对......
  • AutodL训练yolov9
    AutodL训练yolov9全过程1、租借Autodl服务器:AutoDL算力云|弹性、好用、省钱。租GPU就上AutoDL选择环境,直接选择镜像,yolov9官方2、创建完成:点击Jupyterlab进入服务器,到这里服务器租用完成2、下载yolov9官网代码:https://github.com/WongKinYiu/yolov93、进入服务器,上......
  • 计算机毕业设计django+vue基于水果超市管理系统【开题+论文+程序】
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展和电子商务的普及,传统零售业正面临着前所未有的挑战与机遇。水果超市作为日常生活中不可或缺的一部分,其管理模式亟......
  • 计算机毕业设计django+vue音乐网站的设计与实现【开题+论文+程序】
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着互联网的飞速发展,音乐已成为人们日常生活中不可或缺的一部分,数字音乐平台的兴起更是极大地丰富了人们的音乐获取方式。传统的音乐播放......
  • 计算机毕业设计django+vue的献血管理系统【开题+论文+程序】
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着社会对公益事业的日益重视,无偿献血作为保障医疗用血安全、充足的重要一环,其管理效率与服务质量直接关系到医疗体系的稳健运行及公众健......