数据结构与算法——三种基础排序算法C#实现(冒泡排序、选择排序、插入排序)
我们都说程序就是数据加算法,即数据和对数据进行操作的流程。
而对计算机中所存储的数据进行的最普遍的两种操作就是排序和查找。
现在我们就使用C#语言实现三种基础的排序算法——冒泡排序、选择排序、插入排序。
首先我们定义一个能够支持我们创建自定义排序规则的数据结构。我们使用C#的类来作为我们实现的对象,在这个类中维护着一个数组。
其定义如下代码:
1 using System; 2 3 namespace DataStructuresandAlgorithms 4 { 5 6 // 用来承载我们实验的自定义类 7 public class CArray 8 { 9 // 核心的数组,用于对数据的存储和操作 10 private int[] arr; 11 // 用于标识当前对象所存储的值的个数 12 private int elements; 13 // 用于向外界返回此实例最大存储数据个数 14 // 因为数组的大小固定,所以此值在实例被初始化后就是固定的 15 // 此属性用于验证,但我们不是很需要 16 //readonly int size; 17 18 // 构造函数,参数即为该实例内部维护的数组的长度 19 public CArray(int size) 20 { 21 arr = new int[size]; 22 //this.size = size; 23 elements = 0; 24 } 25 26 // 此方法用于向对象内存储数据 27 public int Insert(int item) 28 { 29 arr[elements] = item; 30 return elements++; 31 } 32 33 // 此方法用于显示当前实例存储了哪些数据 34 public void DisplayElements() 35 { 36 foreach (int item in arr) 37 Console.Write(item + " "); 38 } 39 40 // 此方法用于完全清除当前实例存储的数据 41 public void Clear() 42 { 43 for (int i = 0; i < arr.Length; i++) 44 arr[i] = 0; 45 elements = 0; 46 } 47 48 // 冒泡排序 49 public void BubbleSort() 50 { 51 // TDO 暂不实现 52 } 53 // 选择排序 54 public void SelectSort() 55 { 56 // TDO 暂不实现 57 } 58 // 插入排序 59 public void InsertSort() 60 { 61 // TDO 暂不实现 62 } 63 } 64 }
有了我们自定义的一个类来作为数据结构,我们就可以实现排序了。
排序算法都是浮云,大家需要从本质上理解:就是把多个值分成两个来比较,经过多次的划分和比较后确定这些值的排列顺序。
冒泡排序:通过相邻两个值的大小比较(多次),保证数值排序为从小到大的排序方法。
效果及实现原理:外层的数列个数次的循环,每次循环会将最大的数值“冒泡”到右端,因为是相邻的两两比较。
具体实现:双重循环,外层数列个数次,保证每一个数值都处于正确位置(因为每循环一次,至少会确定一个数值的正确位置),内层从数列个数次逐渐减少次数,因为每一次外层循环会确定最大值、倒数第二大值……我们在下一次循环就可以忽略掉他们。
下图为冒泡排序过程中每进行完一次外层循环数列的排序情况:
下图为全部循环的部分结果:
很明显:冒泡排序是通过逐个确定最大值来对数列进行排序的。
我们使用代码来说明这个问题(下面就是冒泡排序的一般写法):
1 // 冒泡排序 2 public void BubbleSort() 3 { // 外层为数列数值个数次的循环 4 for (int i = elements - 1; i >= 1; i--) 5 { // 内层次数主义递减 6 for (int j = 0; j <= i - 1; j++) 7 { // 两两比较,如果后者比前者大则交换位置 8 // 最终会呈现大的数值逐个“冒泡”到数列右端 9 if (arr[j + 1] < arr[j]) 10 { 11 int temp = arr[j]; 12 arr[j] = arr[j + 1]; 13 arr[j + 1] = temp; 14 } 15 } 16 } 17 }
后面我会将整个代码和贴出,其中的冒泡排序经过了一定程度的优化。
选择排序:通过逐个确定最小值进行的排序。
和冒泡排序不同,这种排序思路更为清晰:拿出一个值和数列中的其他值比较,完成整次比较后,它如果是最小的,就放到最左边,如果在比较途中发现比它更小的值,那么该更小的值会作为新的比较对象。
直接上代码可能大家更容易理解:
1 // 选择排序 2 public void SelectSort() 3 { // 外层数值个数次循环,保证排序结果正确 4 for (int i = 0; i < elements; i++) 5 { // 内层循环次数递减,因为每次外循环结束后都会确定一个最小值 6 // 再一次循环时就可以忽略那个值了 7 8 // 假定第二个位置(第二次及以后的循环会排除已确定的最值)上的值是最小值 9 // 将索引记录下来,最后会用到,此值也会被动态修改(如果循环过程中发现新的最值) 10 int index = i; 11 for (int j = i + 1; j < elements; j++) 12 { //进行循环,发现新的最小值后则更新最小值,并记录索引 13 if (arr[index] > arr[j]) 14 index = j; 15 } 16 // 最值找到后将最小值放到最左边(忽略已经确定的最值) 17 int temp = arr[i]; 18 arr[i] = arr[index]; 19 arr[index] = temp; 20 } 21 }
我们再看一看执行过程中数列的变化:
我们来看看更细微的变化:
由于这个数列本身的排序比较规则,不能很好地说明问题,大家可以自己试一下。
大家可能会觉得疑惑:选择排序也可以逐个确定最大值,为什么我会将其和冒泡排序用这种方式区分呢?这个其实没什么好说的,大家的理解不一样,也可以理解为:
冒泡排序和选择排序都是通过逐个确定最值来进行排序,不同的是冒泡排序是相邻两两数值比较,选择排序不是如此。
最后给大家介绍一种比较基础的排序。
插入排序:通过使逐渐增加个数的数列段有序而最终达到排序的目的。
大家可能会觉得绕口,这不能怪我,我是文青嘛。简单来说吧:就像我们玩纸牌或麻将牌,我们手上有多张牌时,我们会将新拿到手的牌放到最适合它的位置。比如我们有大小为1、5的纸牌,当拿到3号纸牌时,我们会将它插入到1和5中间,而如果我们拿到6纸牌,我们则会将它放到5后面。
具体到数列排序上,会造成的效果是:前2个数值有序、前3个数值有序、前4个数值有序……一直到整个数列有序。
先看排序时数列变化:
大家看看代码就会容易理解了:
1 // 插入排序 2 public void InsertSort() 3 { // 外循环是老规矩 4 for (int i = 1; i < elements; i++) 5 { // 内层多次循环解决数列段排序问题 6 // 保存最右边的数值(将要插入已排序数列的值) 7 int temp = arr[i]; 8 // 新索引用于区分需要排序的原始数列 9 int j = i; 10 11 // 如果在已排好序的数列段中还没有找到比新数值小的数值 12 while (j > 0 && temp < arr[j - 1]) 13 { // 将比新数值大的数值向后移 14 arr[j] = arr[j - 1]; 15 j--; 16 } 17 // 如果在已排好序的数列段中找到了比新数值小的数值 18 // 将数值替换到此位置 19 arr[j] = temp; 20 } 21 }
我将完整代码贴上来供大家参考:
1 using System; 2 3 namespace DataStructuresandAlgorithms 4 { 5 // 用来承载我们实验的自定义类 6 public class CArray 7 { 8 private int[] arr; 9 private int elements; 10 11 public CArray(int size) 12 { 13 arr = new int[size]; 14 elements = 0; 15 } 16 17 public int Insert(int item) 18 { 19 arr[elements] = item; 20 return elements++; 21 } 22 23 public void DisplayElements() 24 { 25 foreach (int item in arr) 26 Console.Write(item + " "); 27 } 28 29 public void Clear() 30 { 31 for (int i = 0; i < arr.Length; i++) 32 arr[i] = 0; 33 elements = 0; 34 } 35 36 // 冒泡排序 37 public void BubbleSort() 38 { 39 int temp = 0; 40 bool jx = true; 41 for (int i = elements - 1; jx && i >= 1; i--) 42 { 43 jx = false; 44 for (int j = 0; j <= i - 1; j++) 45 { 46 if (arr[j + 1] < arr[j]) 47 { 48 temp = arr[j]; 49 arr[j] = arr[j + 1]; 50 arr[j + 1] = temp; 51 jx = true; 52 } 53 //Console.WriteLine(); 54 //DisplayElements(); 55 } 56 Console.WriteLine(); 57 DisplayElements(); 58 } 59 } 60 // 选择排序 61 public void SelectSort() 62 { 63 for (int i = 0; i < elements; i++) 64 { 65 int index = i; 66 for (int j = i + 1; j < elements; j++) 67 { 68 if (arr[index] > arr[j]) 69 index = j; 70 71 //Console.WriteLine(); 72 //DisplayElements(); 73 } 74 int temp = arr[i]; 75 arr[i] = arr[index]; 76 arr[index] = temp; 77 Console.WriteLine(); 78 DisplayElements(); 79 } 80 } 81 // 插入排序 82 public void InsertSort() 83 { 84 for (int i = 1; i < elements; i++) 85 { 86 int temp = arr[i]; 87 int j = i; 88 while (j > 0 && temp < arr[j - 1]) 89 { 90 arr[j] = arr[j - 1]; 91 j--; 92 } 93 arr[j] = temp; 94 Console.WriteLine(); 95 this.DisplayElements(); 96 } 97 } 98 static void Main(string[] args) 99 { 100 CArray ca = new CArray(10); 101 Random rnd = new Random(100); 102 for (int i = 0; i < 10; i++) 103 ca.Insert(rnd.Next(0, 100)); 104 105 // 排序前 106 ca.DisplayElements(); 107 Console.WriteLine(); 108 109 // 排序 110 ca.BubbleSort(); 111 //ca.InsertSort(); 112 //ca.SelectSort(); 113 114 // 排序后 115 Console.WriteLine(); 116 Console.WriteLine(); 117 ca.DisplayElements(); 118 Console.Read(); 119 } 120 } 121 }
这次的基础排序算法就为您介绍到这里。
(最后编辑时间2012-08-21 19:20:50)