目录
选择排序:
选择排序的操作步骤
-
初始化:
- 设定一个待排序数组
arr
,数组长度为n
。
- 设定一个待排序数组
-
排序过程:
- 外层循环:从
0
到n-2
,控制当前的排序位置i
。- 内层循环:从
i+1
到n-1
,用于寻找最小元素的位置。- 在内层循环中,比较当前位置
i
的元素与从i+1
到n-1
的每个元素。 - 将比较后比 i 位置值大的数与当前位置
i
的元素交换。
- 在内层循环中,比较当前位置
- 重复:继续执行外层循环,直到排序完成
- 内层循环:从
- 外层循环:从
作用:将一组数据从小到大排列。
思想:先从前面第一个数开始往后面比较(利用for循环),如果后面的数比这个数还小,则交换数据,再用这个小的数去和后面剩下的数比较,第一个数比较完后,第一个位置就存放了最小的数,在第一个for循环里面再添加一个for循环,开始比较第二个数,注意此时只需要从第三个数开始比较,直到比完,依次类推,越往后需要比较的次数越少,最后一个数就在前一次的比较中已经将最大值放在了最后一位,所以外部for循环主要换到 第 len-2个位置就行了 (len- 2 < len -1) 。
1 #include <stdio.h>
2 int main()
3 {
4 int a[] = {1,2,3,4,5,6,7,8,9,0};
5 int len = sizeof(a) / sizeof(a[0]);
6 int i,j;
7 for(i = 0;i < len -1;i++)//1-10个位置,i代表在数组中的对应位置
8 {
9 for(j = i + 1;j < len;j++)//j=i+1从a[i]后面一个开始比较,直至最后一个
10 {
11 int num;
12 if(a[i] > a[j])//如果后面的数有比a[i]还小的数,则将大数放在后面,这样小数又到前面了,依次类推比较,最后小数在前,大数在后
13 {
14 num = a[i];
15 a[i] = a[j];
16 a[j] = num;
17 }
18 }
19 }
20 for(i = 0;i < len; i++)
21 {
22 printf("%d\n",a[i]);
23 }
24
25 }
26
冒泡排序:
操作步骤
-
开始排序:
- 从数组的第一个元素开始,比较相邻的两个元素。
- 如果前一个元素大于后一个元素,则交换它们的位置。
-
重复比较与交换:
- 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。
- 在这一轮比较结束时,最大的元素会被“冒泡”到数组的末尾。
-
持续进行:
- 针对所有的元素重复以上的步骤,但每次循环都忽略已经排序好的末尾部分。
- 持续对越来越少的元素重复上述步骤,直到没有任何一对数字需要比较。
-
排序完成:
- 当整个数组都按照升序(或降序)排列时,排序过程结束。
作用:将一组数据从小到大排列。
思想:冒泡法一次冒泡只将一个数送给到合适位置,将大数往后送,外层循环控制冒几次泡(也就是从当前位置往后对比几趟),每次冒泡随着次数越多,后面大数确定位置越多,从头开始比较 次数也越少。冒泡法只跟自己的后面一个比较,如果后面的数小,则互换,将大数往后面运输。
总结 :一次冒一个数,相邻两个元素两两比较,小的放前,大的换后。
1 #include <stdio.h>
2 int main()
3 {
4 int i,j,temp;
5 int a[] = {9,8,7,6,5,4,3,2,1,0};
6 int len = sizeof(a) / sizeof(a[0]);
7
8 for(i = len - 1;i > 0;--i)//冒泡法一次只将一个数送到合适的位置,即将大数往后面位置送,确保最后的数最大
9 {
10 for(j = 0;j < i;j++)//控制每次比较多少次,越往后比的次数越少,后面的大数就已经确定了
11 {
12 if(a[j] > a[j + 1])//只跟自己身后的数比较,后面的数如果比他自身小,则互换数值(即将大数忘后面传递)(注意是只跟自己身后的数比较,因此a[j]与a[j+1]>
13
{
14 temp = a[j];
15 a[j] = a[j + 1];
16 a[j + 1] = temp;
17 }
18 }
19 }
20
21 for(i = 0; i < len;i++ )
22 {
23 printf("%4d",a[ui]);
24 }
25
26 return 0;
27
28 }
插入排序
操作步骤
-
初始化:
- 从第二个元素(索引为1,第一个无对比,直接放入)开始,将其与前面的元素进行比较并插入到正确的位置。
-
遍历数组:
- 从数组的第二个元素(索引为1)开始,依次对每个元素进行插入操作。设当前元素为 key。
- 内层循环:利用while(j > 0&&t<b[j-1])循环在已排序的部分中,从后向前遍历,找到插入
key
的正确位置。具体步骤:- 比较
key
与当前元素。如果key
比当前元素小,则将当前元素向后移动一位。 - 继续比较,直到找到合适的插入位置或已遍历完已排序部分。
- 比较
-
插入:
- 将
key
插入到找到的位置。
- 将
-
重复:
- 对数组中的所有元素重复以上步骤,直到所有元素都被插入到正确的位置,数组完全有序。
非原地插入法
思想:首先创建两个一样的数组,一个存放原始数据,一个存放排序过后的数据,从原始数组a中一个一个取出数据,暂放到b对应的位置去,在对应位置后,要与b数组在此之前的数据全部比较一遍,如果前面的值比自身大,则数值互换,同时while判断条件中确保 j>=0,比完就结束,即找到该数值在b数组中的准确位置,插入排序也有两个循环,一个for循环一个while(上面两种排序方式都是两个for循环)外层for循环控制从a中一个一个数依次取出,直至取完,while循环确定插入的位置。
1 #include <stdio.h>
2 int main()
3 {
4 int t,i,j;
5 int a[] = {9,8,7,6,5,4,3,2,1,0};
6 int b[10];//创建一个新的一模一样的数组,用于后续存放
7 int len = sizeof(a) / sizeof(a[0]);
8 for(i = 0;i < len;i++)//从a数组中循环取出第i个数
9 {
10 t = a[i];//用t来存放取得的值
11 j = i;//同时在b数组中找到对应的位置,然后依次往前面比较,看看自己合适在哪
12 while(j > 0&&t<b[j-1])//跟自己前面的每一个数比较,如果前面的数比自己大则互换数值,同时while循环判断条件检查是否j=0了(即此时已经和自身前面所有的数比较过了,找到确定位置
13 {
14 b[j] = b[j-1];
15 j--;
16 }
17 b[j] = t;//此时j--了已经在最合适的位置,将数值放进去
18 }
19 for(i = 0;i < len;i++)
20 {
21 printf("%3d",b[i]);
22 }
23 putchar('\n');
24 return 0;
25 }
原地插入排序
原地插入排序只有一个数组,在本数组中进行数据排列替换,空间复杂度比非原地插入法更低。
#include <stdio.h>
2 int main()
3 {
4 int t,i,j;
5 int a[] = {9,8,7,6,5,4,3,2,1,0};
6 int len = sizeof(a)/sizeof(a[0]);
7
8 for(i = 0;i < len;i++)
9 {
10 t = a[i];
11 j = i;
12 while(j>0&&t<a[j-1])
13 {
14 a[j] = a[j-1];
15 j--;
16 }
17 a[j] = t;
18 }
19 for(i = 0;i < len;++i)
20 {
21 printf("%d",a[i]);
22 }
23
24 putchar('\n');
25 return 0;
26 }
~
二分查找
算法步骤:
- 初始化左右位置 begin 和 end,分别表示数组的开始和结束位置。
- 计算中间位置
mid
。 - 比较目标值与
a[mid]
:- 如果相等,break退出循环。
- 如果目标值小于
a[mid]
,end = mid -1,在左半部分继续查找。 - 如果目标值大于
a[mid]
,begin = mid + 1在右半部分继续查找。 - 最后通过if检查begin和end大小,判断是否查找到数据,并输出。
1 #include <stdio.h>
2 int main()
3 {
4 int begin,end,mid,n;
5 int a[] = {1,2,3,4,5,6,7,8,9};
6 begin = 0;
7 end = 8;
8 n = 8;
9
10 while(begin<=end)
11 {
12 mid = (begin + end)/2;
13 if(a[mid]>n)
14 {
15 end = mid - 1;
16 }
17 else if(a[mid]<n)
18 {
19 begin = mid + 1;
20 }else
21 break;
22 }
23 if(begin<=end)
24 {
25 printf("found the num a[%d]\n",mid);
26 }else
27 {
28 printf("not found");
29 }
30
31
32 return 0;
33 }
~
总结
- 定义和用途:二分查找用于在有序数组中快速查找元素,具有 O(\log n)O(logn) 的时间复杂度。
- 算法实现:可以使用迭代或递归方式实现二分查找。
- 注意事项:确保数组有序,避免整数溢出,正确处理边界条件,考虑处理重复元素的需求,并选择适合的实现方式。
掌握这些细节可以帮助我们更有效地在 C 语言中使用二分查找算法,提升程序的性能和稳定性。
字符型数组
数组初始化:
char str[10]; // 定义一个长度为 10 的字符数组
char str[20] = {'a','b','c','d'}; //定义一个数组部分初始化,其余位置补'\0'
char str[] = {'a','b','c','d'} //这个数组中则没有'\0'这个结束标志
char str1[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; // 显式初始化
char str2[] = "Hello"; // 隐式初始化
字符串终止符:
在 C 语言中,字符串以 '\0'
(空字符)作为结束符。这意味着实际存储的字符数比数组的大小小 1,因为最后一个字符是用来标识字符串的结束。
注意
1.字符串 是 当做字符数组来处理的。
2.字符串 有一个专门的结束标志 '\0'
3.处理的是字符串,操作的时候,往往以 结束标志 为 操作依据
4.处理的是数组,操作的时候,往往以 数组长度 作为操作依据
5.字符数组可以用来存储字符串
而
字符串在内存中存储的方式 也是以 字符数组形式存储的
"hello" --- 'h''e''l''l''o''\0'
实际占用的内存空间,是包含了'\0'
"" //字符串 --- 空字符串 '\0'
gets、puts语句
int puts(const char *s);
功能:
输出一个字符串
参数:
s //表示字符串 -- 指针类型
//字符数组名 s
//字符串常量 "hello"
返回值:
成功 非负数
失败 -1
注意:
puts输出时 自动会加 换行
char *gets(char *s);
功能:
从键盘获得一个字符串
参数:
s //代表就是一块存储空间 --- 需要的是一个一维字符型数组的数组名
返回值:
成功 s
失败 NULL
1 #include <stdio.h>
2 int main()
3 {
4 char s[] = "hello";
5 char s1[] = {'w','o','r','l','d'};//注意这里单个字符存储,没有存入‘\n’结束标志,如果你要使用s1字符数组用puts输出,当作字符串使用,它需要检测到‘\0’才会结束,但是是
中没有,所以它会往空间后面一直输出 知道遇到'\0'结束标志
6
7 puts(s);
8 puts(s1);
9 return 0;
10
11 }
排序总结:
选择排序:
从确定位置依次比较,选择小数往前面确定的位置填进去。关键词:定位置
冒泡排序:
从第一个数开始往自身后一个比较,大数往后放,直至填满。 关键词:大往后
插入排序:
从第二个数开始往前比,找到自身合适位置,大往后 关键词:往前比,找位置