C#数据结构与算法揭秘16

简介:

这节我们就用的最多的算法——排序发起重点的讨论。  

常见的排序分为冒泡排序,快速排序,直接插入排序 ,希尔排序,基数排序 ,简单选择排序 ,堆排序  等等。

一、冒泡排序

冒泡排序(Bubble Sort)的基本思想是:将相邻的记录的关键码进行比较,若前面记录的关键码大于后面记录的关键码,则将它们交换,否则不交换。

设待排序的顺序表 sqList 中有 n 个记录,冒泡排序要进行 n-1 趟,每趟循环均是从最后两个记录开始。 第 1 趟循环到第 2 个记录的关键码与第 1 个记录的关键码比较后终止, 第 2 趟循环到第 3 个记录的关键码与第 2 个记录的关键码比较结束后终止。一般地,第 i 趟循环到第 i+1 个记录的关键码与第 i 个记录的关键码比较后终止,所以,第 n-1 趟循环到第 n 个记录的关键码与第 n-1 个记录的关键码比较后终止。

冒泡排序算法的实现如下所示,算法中记录的比较表示记录关键码的比较,顺序表中只存放了记录的关键码: 实现的源代码如下:


//进行冒泡排序的方法
public void BubbleSort(SeqList<int> sqList) 
    { 
       ///进行交换的变量
         int tmp; 
         for (int i = 0; i < sqList.Last; ++i) 
         { 
              for (int j = sqList.Last - 1; j >= i; --j) 
              { 
                 //如果后面比前面大,  就交换
                  if (sqList[j + 1] < sqList[j]) 
                  { 
                      tmp = sqList[j + 1]; 
                      sqList[j + 1] = sqList[j]; 
                      sqList[j] = tmp; 
                  } 
              } 
         } 
}
//由于是双层循环 算法的时间的复杂度是O(n^2)

冒泡排序算法的最好情况是记录已全部排好序,这时,循环 n-1 次,每次循环都因没有数据交换而退出。因此,冒泡排序算法在最好情况下的时间复杂度为O(n)。

总的移动次数为比较次数的 3 倍, 因为被进行一次比较, 需要进行 3 次移动。因此,冒泡排序算法在最坏情况下的时间复杂度为O(n2)。
冒泡排序算法只需要一个辅助空间用于交换记录,所以,冒泡排序算法是一种稳定的排序方法。什么是稳定的排序算法,就是前面与后面的数字相等的话,不用交换。

二、快速排序

快速排序(Quick Sort)的基本思想是:通过不断比较关键码,以某个记录为界(该记录称为支点) ,将待排序列分成两部分。其中,一部分满足所有记录的关键码都大于或等于支点记录的关键码, 另一部分记录的关键码都小于支点记录的关键码。把以支点记录为界将待排序列按关键码分成两部分的过程,称为一次划分。对各部分不断划分,直到整个序列按关键码有序为止。

设待排序的顺序表 sqList 中有 n 个记录,一般地,第一次划分把第一个记录作为支点。首先,把支点复制到一个临时存储空间中,并设两个指示器,一个指示器 low,指向顺序表的低端(第一个记录所在位置) ,一个指示器 high,指向顺序表的高端(最后一个记录所在位置) 。然后,从 high 所指向的记录开始,将记录的关键码与支点(在临时存储空间中)的关键码进行比较,如果 high 所指向的记录的关键码大于支点的关键码,high 指示器向顺序表的低端方向移动一个记录的位置,否则,将 high 所指的记录复制到 low 所指的存储空间中。接着,又将 low 移到下一个记录,从 low 所指向的记录开始,将记录的关键码与临时存储空间的记录的关键码进行比较, 如果 low 所指向的记录的关键码小于临时存储空间的记录的关键码,low 指示器向顺序表的高端方法移动一个记录的位置,否则,将 low 所指的记录复制到 high 所指的存储空间中,high 指示器向顺序表的低端移动一个记录的位置。如此重复,直到 low 和 high 指示器指向同一个记录,
将临时空间的记录赋给 low 所指向的存储空间,第一次划分结束。如图所示:


快速排序的算法实现如下所示,算法中记录的比较表示记录关键码的比较顺序表中只存放了记录的关键码。相应源代码如下:


1 public void QuickSort(SeqList<int> sqList, int low, int high) 
 2     { 
 3          //头指针
 4           int i = low; 
 5          //尾指针
 6           int j = high; 
 7            //关键码
 8           int tmp = sqList[low]; 
 9           //头指针尾指针位置的变换
10           while (low < high) 
11           { 
12                while ((low < high) && (sqList[high] >= tmp)) 
13                { 
14                     --high; 
15                } 
16                sqList[low] = sqList[high]; 
17                ++low; 
18                while ((low < high) && (sqList[low] <= tmp)) 
19                { 
20                     ++low; 
21                } 
22                sqList[high] = sqList[low]; 
23                --high; 
24            } 
25            sqList[low] = tmp; 
26             //新一轮的变换
27            if (i < low-1) 
28            { 
29                 QuickSort(sqList, i, low-1); 
30            } 
31            //新一轮的递归
32            if (low+1 < j) 
33            { 
34                 QuickSort(sqList, low+1, j); 
35            } 
36     } 
37 }
38 //由于用到递归 循环 时间复杂度是O(nlog2n)

快速排序算法的时间复杂度和每次划分的记录系很大。 如果每次选取的记录都能均分成两个相等的子序列,这样的快速排序过程是一棵完全二叉树结构(即每个结点都把当前待排序列分成两个大小相当的子序列结点,n个记录待排序列的根结点的分解次数就构成了一棵完全二叉树) ,这时分解次数等于完全二叉树的深度log2n。每次快速排序过程无论把待排序列这样划分,全部的比较次数都接近于n-1 次,所以,最好情况下快速排序的时间复杂度为O(nlog2n) 。快速排序算法的最坏情况是记录已全部有序,此时n个记录待排序列的根结点的分解次数就构成了一棵单右支二叉树。 所以在最坏情况下快速排序算法的时间复杂度为O(n2)。一般情况下,记录的分布是随机的,序列的分解次数构成一棵二叉树,这样二叉树的深度接近于log2n,所以快速排序算法在一般情况下的时间复杂度为O(nlog2n) 。 另外,快速排序算法是一种不稳定的排序的方法。不稳定排序的算法 ,前后数字相等要交换。

这节,我们介绍了快速排序和冒泡排序。下节,我们介绍直接插入排序和希尔排序。嘎嘎。


目录
相关文章
|
10月前
|
开发框架 算法 搜索推荐
C# .NET面试系列九:常见的算法
#### 1. 求质数 ```c# // 判断一个数是否为质数的方法 public static bool IsPrime(int number) { if (number < 2) { return false; } for (int i = 2; i <= Math.Sqrt(number); i++) { if (number % i == 0) { return false; } } return true; } class Progr
146 1
|
2月前
|
缓存 算法 安全
剖析‘共享文件夹只让指定用户看到’的 C# 精妙算法
在数字化时代,信息精准共享与管控至关重要。基于角色的访问控制(RBAC)算法通过将用户划分为不同角色并分配权限,确保“共享文件夹只让指定用户看到”。本文以C#代码为例,展示如何实现这一目标,并探讨大规模应用中的动态变更、性能优化和安全性挑战。RBAC算法结合C#编程,助力高效、安全的协作环境。
|
3月前
|
存储 监控 算法
企业内网监控系统中基于哈希表的 C# 算法解析
在企业内网监控系统中,哈希表作为一种高效的数据结构,能够快速处理大量网络连接和用户操作记录,确保网络安全与效率。通过C#代码示例展示了如何使用哈希表存储和管理用户的登录时间、访问IP及操作行为等信息,实现快速的查找、插入和删除操作。哈希表的应用显著提升了系统的实时性和准确性,尽管存在哈希冲突等问题,但通过合理设计哈希函数和冲突解决策略,可以确保系统稳定运行,为企业提供有力的安全保障。
|
4月前
|
算法 C#
C#常见的四种经典查找算法
C#常见的四种经典查找算法
|
4月前
|
算法 C# 索引
C#线性查找算法
C#线性查找算法!
|
5月前
|
存储 算法 C#
C#哈希查找算法
C#哈希查找算法
|
5月前
|
算法 C# 索引
C#二分查找算法
C#二分查找算法
|
5月前
|
机器学习/深度学习 算法 数据挖掘
使用C# 实现期望最大化算法
使用C# 实现期望最大化算法
78 0
|
6月前
|
存储 算法 C#
C#二叉搜索树算法
C#二叉搜索树算法
|
7月前
|
存储 C#
揭秘C#.Net编程秘宝:结构体类型Struct,让你的数据结构秒变高效战斗机,编程界的新星就是你!
【8月更文挑战第4天】在C#编程中,结构体(`struct`)是一种整合多种数据类型的复合数据类型。与类不同,结构体是值类型,意味着数据被直接复制而非引用。这使其适合表示小型、固定的数据结构如点坐标。结构体默认私有成员且不可变,除非明确指定。通过`struct`关键字定义,可以包含字段、构造函数及方法。例如,定义一个表示二维点的结构体,并实现计算距离原点的方法。使用时如同普通类型,可通过实例化并调用其成员。设计时推荐保持结构体不可变以避免副作用,并注意装箱拆箱可能导致的性能影响。掌握结构体有助于构建高效的应用程序。
203 7