排序1+2:交换排序(ExchangeSort),选择排序(SelectSort)和插入排序(Insertsort)
交换排序,插入排序和选择排序都是很简单也很基础的排序算法。在世面上各种各样的算法和数据结构的书中都很轻易地找的到他们的踪影。在这儿写出来不外乎是加深自己的印象,也为有需要的朋友做一个参考。
1 交换排序
交换排序是一种很简单的排序方法。其主要思想如下:
(1)利用要排序范围中的第0个数据d[i]与范围中其它数据d[j]相比较。如果前面的数据比后面大,那么就交换这两个数据(就是把较小的数据放在第0个位置)。然后再和排序范围内下一个数据d[j+1]相比较。依此类推。
(2)当执行完步骤(1)后,最小值即位于范围中的第0个位置。然后在剩下的数据中找到一个最小的,放在第1个位置,这样循环查找下去直到所有数据结束,最后可以得到由小到大的排序结果。
交换排序的思想和冒泡排序的思想很类似,实现的代码也非常相似。下面是一个简单的说明例子。
假设要排序的数据是:6 2 5 1 3 4
步骤一:
因为6>2,所以2和6交换
2 6 5 1 3 4
步骤二:因为2<5,所以不交换
2 6 5 1 3 4
步骤三:因为2>1,所以交换
1 6 5 2 3 4
步骤四:因为1<3,所以不交换
1 6 5 2 3 4
步骤五:因为1<4,所以不交换
1 6 5 2 3 4
这样我们叫找到了最小值1,按照同样的办法,就可以找到第二个,第三个最小值。。完成排序。
实现代码非常简单,如下所示:
/// 交换排序的思想非常简单,从第一个数据开始,在剩下的数据中找
/// 比它小的数据,如果找到了,就交换两者。
/// 第一次查找可以找到最小的数据,和第0个数据交换
/// 第二次在剩下的n-1个数据中查找,找个最小的和第一个数据交换
/// 依次交换剩下的所有数据使之有序
/// </summary>
/// <param name="myArray"></param>
public static void ExchangeSort(int [] myArray)
{
int i, j;
for(i=0; i<myArray.Length-1; i++) //从第0个数据开始
{
for(j=i+1; j<myArray.Length; j++)//在剩下的数据中循环
{
if(myArray[j] < myArray[i]) //如果有比它小的,交换两者
{
Swap(ref myArray[j], ref myArray[i]);
}
}
}
}
2 选择排序
选择排序也是很简单的排序方法之一。其主要思想如下:
(1)第一次在数组中查找出最小的值a[i],将其和第0个位置交换。
(2)此时剩下n-1个值,同样从中找出最小的值a[j],a[j]和第一个数据交换
(3)重复上面的步骤,在剩下的范围中找出最小的值和最小数组下标的值进行交换。
一般会设置一个额外变量small来记录最小值的下标,以便于在循环之后,交换指定位置和最小值位置的值。根据上面的描述,我们可以很容易地就写出选择排序的算法。
/// 选择排序的中心思想是每次都从未排序的数据中选出最小的数据,
/// 和未排序数据的第一个数据交换。
/// 第一次选出最小的数据放在第0个位置
/// 第二次在剩下的n-1个数据中选出最小的数据放在第一个位置
/// 依次下去,将所有数据排序
/// </summary>
/// <param name="myArray"></param>
public static void SelectSort(int [] myArray)
{
int i, j, small;
for(i=0; i<myArray.Length-1; i++) //数据起始位置,从0到倒数第二个数据
{
small = i; //记录最小数据的下标
for(j=i+1; j<myArray.Length; j++) //在剩下的数据中寻找最小数据
{
if(myArray[j] < myArray[small])
{
small = j; //如果有比它更小的,记录下标
}
}
Swap(ref myArray[i], ref myArray[small]); //将最小数据和未排序的第一个数据交换
}
}
3 插入排序
插入排序也是一种原理非常简单的排序方法,属于插入方法的排序。其主要思想如下:
(1)首先从第一个数据开始,将该值插入到其前面已经排好序的数据当中。插入的位置是第一个大于该数据的记录的前面。如果没有大于它的数据,就将其放在排好序的数据的最后。由于现在排序尚未开始,因此只有第1个元素。
(2)接着是第二个元素,用步骤1的方法插入到大于它的数的前面。现在第一个,第二个数据都是有序的了。
(3)依次可以排第三个,第四个数据,直到所有的数据完全排好序。可以从下面例子看出详细的过程。
还是假设要排序的数字为:6 2 5 1 3 4
步骤1:移动第一个
6 2 5 1 3 4
步骤2:移动第二个,因为2<6,所以将2放在6前面
2 6 5 1 3 4
步骤3:移动第三个,因为2<5<6,所以将5放在6前面
2 5 6 1 3 4
步骤4:移动第四个,因为1<2<5<6,所以将1放在最前面
1 2 5 6 3 4
步骤5:移动第五个,因为2<3<5<6,所以将3放在2后面
1 2 3 5 6 4
步骤6:移动第六个,因为3<4<5<6,所以将4将在3后面
1 2 3 4 5 6
这样所有的数据就都排好序了。
其实现的算法如下:
/// 插入排序的中心思想在于将未排序的数据插入一个有序表中
/// 第一次将第一个数据放入一个有序表中,该有序表只有一个数据
/// 第二次将第二个数据插入有序表中,使之小的在前,大的在后
/// 第三次将第三个数据插入有序表中
/// 依次下去,将所有数据放入有序表中
/// </summary>
/// <param name="myArray"></param>
public static void InsertSort(int[] myArray)
{
int i, j, temp;
for(i=1; i<myArray.Length; i++)
{
temp = myArray[i]; //保存当前数据
j = i-1;
//将数据插入有序表中,如果表中的数据比该数据大,
//那么就依次向后移动有序表中的数据,直到找到第一个比它小的数据,
//将它放在那个数据后面
while(j>=0 && myArray[j]>temp)
{
myArray[j+1] = myArray[j];
j--;
}
myArray[j+1] = temp; //将数据插入有序表中
}
}
4 效率比较
在实现这三种算法以后,这三种算法都是O(n^2)的算法。效率并不高。还是做个小小的试验来验证一下效率,还是使用1+1中的随机数来测试,可以得到下表,看到这几种算法的效率区别。单位为毫秒
500随机数 | 5000随机数 | 20000随机数 | |
基本冒泡 | 1.5625 | 160.9375 | 2457.8125 |
交换排序 | 1.5625 | 118.75 | 1895.3125 |
选择排序 | 1.5625 | 68.75 | 1081.25 |
插入排序 | 1.5625 | 34.375 | 543.75 |
从上面的表格中可以看到,插入排序比其余的几种排序方法快得多。在数据量越大的时候越明显。还有更快的排序方法吗?答案是肯定的。
/******************************************************************************************
*【Author】:flyingbread
*【Date】:2007年1月27日
*【Notice】:
*1、本文为原创技术文章,首发博客园个人站点(http://flyingbread.cnblogs.com/),转载和引用请注明作者及出处。
*2、本文必须全文转载和引用,任何组织和个人未授权不能修改任何内容,并且未授权不可用于商业。
*3、本声明为文章一部分,转载和引用必须包括在原文中。
******************************************************************************************/