前言
上一节中我们已经学习了第一个算法:冒泡算法,相信你也有足够的自信继续学习更多的算法。
今天我们就来讲解又一个排序相关的算法:选择排序。
时间复杂度
在进行今天的排序算法讲解之前,我们先补充一个知识点:时间复杂度。
这是数据结构中一个比较重要的知识点,它用来衡量解决问题的算法所需的时间成本,它描述了算法所需操作数量随输入大小的增长速度。
常见的时间复杂度有:
-
常数时间复杂度(O(1)):算法的运行时间不随输入规模增加而增加,无论输入的大小如何,算法的运行时间都保持恒定。例如,访问数组中的一个元素。
-
线性时间复杂度(O(n)):算法的运行时间与输入规模成正比。例如,循环遍历一个长度为n的数组。
-
对数时间复杂度(O(log n)):算法的运行时间与输入规模的对数成正比。例如,二分查找算法。
-
平方时间复杂度(O(n^2)):算法的运行时间与输入规模的平方成正比。例如,两个循环嵌套的算法。
-
指数时间复杂度(O(2^n)):算法的运行时间与输入规模的指数成正比。例如,求解旅行商问题的穷举算法。
至于怎么计算时间复杂度,就是一个比较复杂的问题了,博主这里不专门拿篇幅来讲,感兴趣的可以戳这篇文章,在博主看来比较通俗易懂。
了解了时间复杂度,你也会知道为什么上一篇文章做的优化会有人说在时间复杂度上并没有更多的作用。
选择排序基本原理
- 新建中间商(用于存储变量)
- 依次比较
- 找出极值(极大或者极小)
- 放入目标位置
如果觉得不太清楚的话,可以看图像延时,相信你很快就能get到选择排序的特点。
我相信你现在已经清楚了选择排序的基本原理,现在就让博主带着你用c#来实现一下。
代码实现
首先我们要做的第一步,就是声明一个中间商(临时变量),来记录索引,用于我们和后面的值依次比较。
然后我们通过循环,来让他完成依次比较,来确定本次比较的极值所在的下标,我们通过打印来进行验证。
代码如下:
cs
using System;
class Program
{
static void Main(string[] args)
{
int[] arr = new int[] { 8, 7, 1, 5, 4, 2, 6, 3, 9 };
//每一轮开始,默认索引值是极值
int index = 0;
for (int i = 0; i < arr.Length; i++)
{
//找出这一轮的极值
if (arr[index] < arr[i])//>升序,<降序
index = i;
}
Console.WriteLine(arr[index]);
}
}
我们找出了极致后,就要把值放到它应该待的位置:
cs
using System;
class Program
{
static void Main(string[] args)
{
int[] arr = new int[] { 8, 7, 1, 5, 4, 2, 6, 3, 9 };
//每一轮开始,默认索引值是极值
int index = 0;
for (int i = 0; i < arr.Length; i++)
{
//找出这一轮的极值
if (arr[index] >arr[i])//>升序,<降序
index = i;
}
if(index != 0)//是因为数组是从0开始索引的
{
int temp = arr[index];
arr[index] = arr[0];
arr[0] = temp;
}
for (int i = 0; i < arr.Length; i++)
{
Console.Write(" " + arr[i]);
}
}
}
当然,博主也有另一个版本,会在后续给大家一并展示,这个是从头开始排序,另一个是从末尾开始排序。
因为不太符合我的示意图,怕你混淆了,所以我们先讲示意图的方法。
我们完成第一次排序后,只用进行j轮就可以完成排序,j为数组的长度。
加一个循环嘛,不过要注意,排序过的我们就不排序了,这个就不废话了,冒泡排序中也有一样的道理:
具体看注释,如果有疑问可以私信博主。
cs
using System;
class Program
{
static void Main(string[] args)
{
int[] arr = new int[] { 8, 7, 1, 5, 4, 2, 6, 3, 9 };
for (int j = 0;j<arr.Length;j++)
{
//每一轮开始,默认索引值是极值
int index = j;//从j开始索引
for (int i = j; i < arr.Length; i++)//j是排除已定位的元素
{
//找出这一轮的极值
if (arr[index] > arr[i])//>升序,<降序
index = i;
}
if (index != j)//从j开始索引的,所以如果是j其实就不用变位置
{
int temp = arr[index];
arr[index] = arr[j];
arr[j] = temp;
}
for (int i = 0; i < arr.Length; i++)
{
Console.Write(" " + arr[i]);
}
Console.WriteLine();
}
}
}
当然,博主这里也给你提供另一种倒着排序的代码,但是就不进行过多讲解了。
cs
using System;
class Program
{
static void Main(string[] args)
{
int[] arr = new int[] { 8, 7, 1, 5, 4, 2, 6, 3, 9 };
for (int j = 0;j<arr.Length;j++)
{
//每一轮开始,默认索引值是极值
int index = 0;
for (int i = 0; i < arr.Length-j; i++)//是为了排除已经排列的元素
{
//找出这一轮的极值
if (arr[index] < arr[i])//>升序,<降序
index = i;
}
if (index != arr.Length-1-j)//arr.Length-1-j是选择交换的初始位置
{
int temp = arr[index];
arr[index] = arr[arr.Length-1-j];
arr[arr.Length-1-j] = temp;
}
for (int i = 0; i < arr.Length; i++)
{
Console.Write(" " + arr[i]);
}
Console.WriteLine();
}
}
}
总结
到此我们的选择排序就到此结束,C#基础部分的内容也即将告一段落,博主会在后续带着大家做一个简单的成绩录入系统,然后结束C#基础的学习。
学到目前,你已经快要拜托初学者,成为一名略懂语言的程序猿了。
不过,道阻且长,学习路上,戒骄戒躁,脚踏实地。
请期待我的下一篇博客!