这一篇是基础排序算法和查找算法,排序包含冒泡排序和选择排序,查找包含顺序查找和二分查找,希望大家可以在看完后有所收获,如有知识错误欢迎指正,蟹蟹大家的支持哦!!
一.排序算法:
基础认知:
1.排序的效率:时间和空间(内存)两个方面来看
2.排序方式越稳定(当有两个数值大小相同时,当排完序后,两个数值的位置没有发生改变,即没有发生两个相等值的位置交换现象),耗时少,耗空间小,越好
3.排序的过程无论什么算法都是先比较两个数值的大小,然后再移动两个数据的位置
补充:随机数:包含stdlib.h头文件,在主函数中先写出随机数种子:srand((unsigned)time(NULL));然后要得到随机数的话,需要使用rand函数,后面加上括号,因为这是一个函数。如果没有随机数种子的话,生成的随机数是一样的,无法每次生成不同的随机数,通过取余操作可以实现随机数的范围化生成。
1.冒泡排序:
基础实现原理:比较相邻两个元素的值的大小关系,确定是否要交换位置,随后再移动需要比较的位置元素,继续比较交换,比到最后两个元素,这就将最大或最小的元素移动过去了,这就是一趟,由此我们可以发现只要执行n-1趟(需要排序的元素总数为n个)就可以实现将所有元素排序完毕。
初步代码实现:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
int arr[15] = { 0 };
srand((unsigned)time(NULL));
for (int i = 0; i < 15; i++)
{
arr[i] = rand() % 20;
}
for (int j = 0; j < 15 - 1; j++)
{
for (int i = 0; i < 15 - 1; i++)//待改进行
{
if (arr[i] > arr[i + 1])//若要实现从大到小排序,我们可以将这里的大于号改为小于号,即可实现从大到小排序
{
int temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
}
for (int i = 0; i < 15; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
但是由于排好的没有必要再去比较,所以以上代码每次执行所有元素都比较一次是会降低代码的运行效率的,故对其做以下改进:
将待改进行写为:for (int i = 0; i < 15 - 1-j; i++),因为这样可以实现不再去比较已经排好的元素的大小了,执行一次,说明排好了一个元素的位置,就在下一次排序循环(小循环)内排序位次减一。
再考虑到代码的可移植性,我们可以将代码的15都换为宏名,之后就无论是多大的数组我们都可以进行使用这个代码来进行排序了
2.选择排序:找出需要排序的元素的最大(小)的值,然后放在后面(或前面)
我们可以使用max在记录数组中最大值的下标,而不是使用max来记录最大值,因为我们记录了下标之后我们可以直接通过下标来访问到值,而且还可以通过下标来进行下一步的交换移位操作,而利用max记录最大值就只能得到最大值,无法确定最大值在哪里,从而无法实现下一步的交换操作,也就是无法进行排序操作了。
进一步,使用一趟我们可以排好一个元素,那么我们同样和冒泡排序一样,使用元素数减一趟即可实现排好所有元素的序列
初步代码实现:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
int arr[15] = { 0 };
srand((unsigned)time(NULL));
for (int i = 0; i < 15; i++)
{
arr[i] = rand() % 20;
}
for (int j = 0; j < 15 - 1; j++)//使用十四次循环排十四个数的位置即为排好了全部数
{
int max = j;//假定最大的数是排好的数的下一个,再根据大小来进行换位操作
for (int i = j; i < 15-1; i++)//从j下标数开始进行判断大小操作,将排好的前面几个元素直接跳过
{
if (arr[max] < arr[i + 1])//实现将大于arr[max]的元素不断更换到arr[max]的位置,max从0开始,即从大到小排序
{
int temp = arr[max];
arr[max] = arr[i + 1];
arr[i + 1] = temp;
}
}
}
for (int i = 0; i < 15; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
如果要实现从小到大排序,则只需要将小于号改为大于号即可,为了理解性,将max改为min。
代码改进:
思路:在执行寻找最大数的过程中,以上代码不断执行交换操作,直到最大值,那么最大值之前的交换都是无用功,这时我们就可以仅仅记住每一次的下标即可,并在没有遇到最大值时一直更新最大值的下标,一次执行交换操作即可,这样可以有效加快代码的运行效率,并且在执行仅有一次的交换操作时,如果最大的就是起始元素的话就没必要交换,这样可以进一步实现效率的提升
代码:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
int arr[15] = { 0 };
srand((unsigned)time(NULL));
for (int i = 0; i < 15; i++)
{
arr[i] = rand() % 20;
}
for (int j = 0; j < 15 - 1; j++)
{
int max = j;
for (int i = j; i < 15 - 1; i++)
{
if (arr[max] < arr[i + 1])
{
max = i + 1;
}
}
if (max == j)//如果最大值即为预先确定的那个,就无需进行交换操作了,这样可以加快代码的运行效率
{
continue;
}
int temp = arr[max];
arr[max] = arr[j];
arr[j] = temp;
}
for (int i = 0; i < 15; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
同样,如果要实现从小到大排序,我们就可以将以上代码的小于号改为大于号,为了理解性,也把max改为min。
二.查找算法:
1.顺序查找:
如字面意思,按顺序一个一个进行查找,看是否能找到要寻找的元素。
使用顺序查找的示例代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
int arr[15] = { 0 };
int n ,i= 0;
srand((unsigned)time(NULL));
for (int i = 0; i < 15; i++)
{
arr[i] = rand() % 20;
}
printf("请输入要查找的值:\n");
scanf("%d", &n);
for (i = 0; i < 15; i++)
{
if (arr[i] == n)
{
printf("arr[%d]=%d", i, n);
break;
}
}
if (i == 15)
{
printf("未找到你要查找的元素\n");
}
return 0;
}
2.折半查找:只适用于在已经有序的数列中进行查找
先看中间元素和要寻找的元素是否相等,即是否直接找到,若不相等,则判断该中间数和要查找数的大小关系,之后根据确定的大小关系到符合要求的一半去查找,继续执行前面的操作,直到一直二分到找到或直到二分尽头处仍未找到。
代码示例如下:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
int arr[15] = { 0 };
int n = 0;
srand((unsigned)time(NULL));
for (int i = 0; i < 15; i++)
{
arr[i] = rand() % 20;
}
printf("请输入要查找的值:\n");
scanf("%d", &n);
for (int j = 0; j < 15; j++)
{
for (int i = 0; i < 15 - 1 - j; i++)
{
if (arr[i] > arr[i + 1])
{
int temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
}
for (int i = 0; i < 15; i++)
{
printf("%d ", arr[i]);
}
int left = 0;
int right = 15 - 1;
int mid = 0;
while (left <= right)//当不符合正常区间条件时说明没找到
{
mid = ((right - left) >> 1) + left;//确定中间位置
if (n == arr[mid])
{
printf("\narr[%d]=%d\n", mid, n);
return 0;
}
else if (arr[mid] > n)
{
right = mid - 1;
}
else
left = mid + 1;
}
printf("未找到所要查找的元素\n");
return 0;
}