C#实现(递归和非递归)高速排序和简单排序等一系列排序算法
本人由于近期工作用到了一些排序算法。就把几个简单的排序算法。想冒泡排序,选择排序,插入排序。奇偶排序和高速排序等整理了出来,代码用C#代码实现,而且通过了測试。希望能给大家提供參考。
1.冒泡排序
冒泡排序,是指计算机的一种排序算法,它的时间复杂度是O(n^2),尽管不及堆排序和高速排序时间复杂度为O(nlogn,底数为2)。可是有两个长处:1:编程复杂度低。非常easy实现;2 是具有稳定性,这里的稳定性是指源序列中同样元素的相对顺序仍然保持到排序后的顺序,而堆排序和高速排序都不具有稳定性。
基本概念
冒泡排序(BubbleSort)的基本概念:依次比較相邻两个数,小的在前,大的在后。在第一趟,首先比較第1个数和第2个数,小的放在前面。大的放在后面,然后比較第2个数和第3个数,小的在前,大的在后。如此继续。直到比較最后两个数,小的在前,大的在后,第一趟结束时,就把最大的数放在了最后。在第二趟,仍从第一对数開始比較(由于由于第2个数和第3个数的交换。使第1个数不再小于第2个数),将小数放前。大数放后,一直比較到倒数第二个数(倒数第一个数已经是最大的),第二趟结束,这样在倒数第二个位置得到一个新的最大数,如此循环下去,反复以上过程,直至终于完毕排序。
比方有一个数列10, 33, 2, 4, 55, 6, 12, 34, 456, 66, 43, 23, 65, 1, 345, 61, 76, 31, 43, 76
第一次排序后:10,2,4,33,6,12,34,55,66,43,23,65,1,345,61,76,31,43,76,456
第二次排序后:2,4,10,6,12,33,34,55,43,23,65,1,66,61,76,31,43,76,345,456
第三次排序后:2,4,6,10,12,33,34,43,23,55,1,65,61,66,31,43,76,76,345,456
第四次排序后:2,4,6,10,12,33,34,23,43,1,55,61,65,31,43,66,76,76,345,456
第五次排序后: 2,4,6,10,12,33,23,34,1,43,55,61,31,43,65,66,76,76,345,456
第六次排序后: 2,4,6,10,12,23,33,1,34,43,55,31,43,61,65,66,76,76,345,456
第七次排序后: 2,4,6,10,12,23,1,33,34,43,31,43,55,61,65,66,76,76,345,456
第八次排序后: 2,4,6,10,12,1,23,33,34,31,43,43,55,61,65,66,76,76,345,456
第九次排序后: 2,4,6,10,1,12,23,33,31,34,43,43,55,61,65,66,76,76,345,456
第十次排序后: 2,4,6,1,10,12,23,31,33,34,43,43,55,61,65,66,76,76,345,456
第十一次排序后:2,4,1,6,10,12,23,31,33,34,43,43,55,61,65,66,76,76,345,456
第十二次排序后:2,1,4,6,10,12,23,31,33,34,43,43,55,61,65,66,76,76,345,456
第十三次排序后: 1,2,4,6,10,12,23,31,33,34,43,43,55,61,65,66,76,76,345,456
这样经过13趟排序后这个序列就成为一个有序的数列。
详细实现代码为:
private static void BubbleSort(int[] R)
{
int len = R.Length;
bool flag = false;
for (int i = 0; i < len-1; i++)
{
flag = false;
for (int j = 0; j < len - i-1; j++)
{
if (R[j] > R[j + 1])
{
Swap(ref R[j], ref R[j + 1]);
flag = true;
}
}
if (!flag)
{
break;
}
}
}
private static void Swap(ref int left, ref int right)
{
int temp = left;
left = right;
right = temp;
}
2. 选择排序
每一趟从待排序的元素中选择最小的(最大的)一个元素,顺序放在已排好序的数列的最后,直到待排序的元素派完,选择排序是不稳定的排序。
基本概念
具有n元素的数列能够进行n-1趟直接选择排序得到有序结果,初始状态有序区为空。无序区为R[1...n]
第1趟排序在无序区R[1...n]选择keyword最小的元素R[k],将它与无序区的R[1] 进行交换,使R[1...1]和R[2...n]变为个添加为1新有序区。和无序区的元素个数减去1的新无序区。
第i趟排序開始时,当前有序区和无序区分别为R[1..i-1]和R(1≤i≤n-1)。该趟排序从当前无序区中选出keyword最小的记录 R[k],将它与无序区的第1个记录R交换。
使R[1..i]和R分别变 为记录个数添加1个的新有序区和记录个数降低1个的新无序区。 这样,n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果 .
对于数列 10,33,2,4,55,6,12,34,456,66,43,23,65,1,345, 61,76,31,43,76
第一次排序后:1,33,2,4,55,6,12,34,456,66,43,23,65,10,345,61,76,31,43,76
第二次排序后: 1,2,33,4,55,6,12,34,456,66,43,23,65,10,345,61,76,31,43,76
第三次排序后:1,2,4,33,55,6,12,34,456,66,43,23,65,10,345,61,76,31,43,76
第四次排序后:1,2,4,6,55,33,12,34,456,66,43,23,65,10,345,61,76,31,43,76
第五次排序后:1,2,4,6,10,33,12,34,456,66,43,23,65,55,345,61,76,31,43,76
第六次排序后: 1,2,4,6,10,12,33,34,456,66,43,23,65,55,345,61,76,31,43,76
第七次排序后: 1,2,4,6,10,12,23,34,456,66,43,33,65,55,345,61,76,31,43,76
第八次排序后: 1,2,4,6,10,12,23,31,456,66,43,33,65,55,345,71,76,34,43,76
第九次排序后: 1,2,4,6,10,12,23,31,33,66,43,456,65,55,345,71,76,34,43,76
第十次排序后: 1,2,4,6,10,12,23,31,33,34,43,456,65,55,345,71,76,66,43,76
第十一次排序后: 1,2,4,6,10,12,23,31,33,34,43,43,65,55,345,71,76,66,456,76
第十二次排序后: 1,2,4,6,10,12,23,31,33,34,43,43,55,65,345,71,76,66,456,76
第十三次排序后: 1,2,4,6,10,12,23,31,33,34,43,43,55,65,66,71,76,345,456,76
第十四次排序后: 1,2,4,6,10,12,23,31,33,34,43,43,55,65,66,71,76,76,456,345
第十五次排序后: 1,2,4,6,10,12,23,31,33,34,43,43,55,65,66,71,76,76,345,456
终于经过15次排序后成为有序的数列。
详细实现代码为:
private static void SelectSort(int[] R)
{
int len = R.Length;
int min = 0;
for (int i = 0; i < len - 1; i++)
{
min = i;
for (int j = i + 1; j < len - 1; j++)
{
if (R[min] > R[j])
{
min = j;
}
}
Swap(ref R[i], ref R[min]);
}
}
3. 插入排序
插入排序算法是一种稳定的算法,时间复杂度是O(n^2)。适用于少量数据的排序。插入算法的基本操作就是将一个数据插入到已经排好序的有序数据中。从而得到一个新的,个数加1的有序数据。
插入算法把要排序的数组分为两部分:第一部分包括了数组的全部元素,但将最后一个元素除外。而第二部分就仅仅包括这一个元素,在第一部分排序后,再把最后这个元素插入到此刻已是有序的一部分中。
基本思想
1:每次处理都是将无序序列的第一个元素和有序序列的元素从后面逐一比較,查到合适的插入位置,将该元素插入到有序序列的合适位置。
2:从有序R[1]和无序R[2...n]開始进行排序。
3:处理第i个元素时(i=2,3,…,n) ,数列{R1,R2,...Ri-1}都是有序的。而数列{Ri,Ri+1,...Rn}都是无序的,用Ri 与{R1,R2,...Ri-1}逐个比較。找到合适位置。将Ri插入,
4:反复第三部,共进行n-i次插入处理,数组全部有序
对于数列 10,33,2,4,55,6,12,34,456,66,43,23,65,1,345, 61,76,31,43,76
第一次排序后:10,33,2,4,55,12,34,456,66,43,23,65,1,345,61,76,31,43,76
第二次排序后: 2,10,33,4,55,12,34,456,66,43,23,65,1,345,61,76,31,43,76
第三次排序后: 2,4,10,33,55,12,34,456,66,43,23,65,1,345,61,76,31,43,76
第四次排序后: 2,4,10,33,55,12,34,456,66,43,23,65,1,345,61,76,31,43,76
第五次排序后: 2,3,10,12,33,55,34,456,66,43,23,65,1,345,61,76,31,43,76
第六次排序后: 2,3,10,12,33,34,55,456,66,43,23,65,1,345,61,76,31,43,76
第七次排序后: 2,3,10,12,33,34,55,456,66,43,23,65,1,345,61,76,31,43,76
第八次排序后: 2,3,10,12,33,34,55,66,456,43,23,65,1,345,61,76,31,43,76
第九次排序后: 2,3,10,12,33,34,43,55,66,456,23,65,1,345,61,76,31,43,76
第十次排序后: 2,3,10,12,23,33,34,43,55,66,456,65,1,345,61,76,31,43,76
第十一次排序后: 2,3,10,12,23,33,34,43,55,65,66,456,1,345,61,76,31,43,76
第十二次排序后: 1,2,3,10,12,23,33,34,43,55,65,66,456,345,61,76,31,43,76
第十三次排序后: 1,2,3,10,12,23,33,34,43,55,65,66,345,456,61,76,31,43,76
第十四次排序后: 1,2,3,10,12,23,33,34,43,55,61,65,66,345,456,76,31,43,76
第十五次排序后: 1,2,3,10,12,23,33,34,43,55,61,65,66,76,345,456,31,43,76
第十六次排序后: 1,2,3,10,12,23,31,33,34,43,55,61,65,66,76,345,456,43,76
第十七次排序后: 1,2,3,10,12,23,31,33,34,43,43,55,61,65,66,76,345,456,76
第十八次排序后: 1,2,3,10,12,23,31,33,34,43,43,55,61,65,66,76,76,345,456
共十八次排序后,数组才是全部有序的。
实现代码为:
private static void InsertSort(int[] R)
{
int len = R.Length;
int j = 0;
int temp = 0;
for (int i = 1; i < len; i++)
{
temp=R[i];
j=i-1;
while (j >= 0 && temp < R[j])
{
R[j + 1] = R[j];
j--;
}
R[j + 1] = temp;
}
}
4. 高速排序
高速排序是对冒泡排序的一种改进,它的基本思想是:通过一趟排序将要排序的数列分成独立的两个部分,当中一部分的全部数据都比后一部分的全部数据都要小,然后再按此方法对这两个部分分别进行高速排序,整个排序过程能够递归进行,以次达到整个数列变为有序。
高速排序不是稳定的排序。
算法过程
设要排序的数组为R[1...n],首先随意选取一个元素(通常选择第一个元素)作为关键元素。然后把全部比它小的都放在前面,全部比它大的都放在后面,这个过程成为一趟高速排序。
1. 设置两个变量 low ,high,排序開始的时候low=0,high=n-1;
2. 以第一个数组元素为重要数据key,即key = R[low];
3. 从high開始往前搜索,即由后開始向前搜索,high=high-1,找到第一个小于key的值R[high], 并与R[low] 交换,
4. 从low 開始向后搜索,即由前開始向后搜索,low=low+1,找到第一个大于key的值R[low],并于R[high]交换。
5. 反复3,4.直到low=high.
对于数列 10,33,2,4,55,6,12,34,456,66,43,23,65,1,345, 61,76,31,43,76
初始重要数据key=10;
第一次交换后:1, 33, 2, 4, 55, 6, 12, 34, 456, 66, 43, 23, 65, 1, 345, 61, 76, 31, 43, 76
第二次交换后: 1, 33, 2, 4, 55, 6, 12, 34, 456, 66, 43, 23, 65, 33, 345, 61, 76, 31, 43, 76
第三次交换后: 1, 6, 2, 4, 55, 6, 12, 34, 456, 66, 43, 23, 65, 33, 345, 61, 76, 31, 43, 76
第四次交换后: 1, 6, 2, 4, 55, 55, 12, 34, 456, 66, 43, 23, 65, 33, 345, 61, 76, 31, 43, 76
这样low=high=4
再把R[low]=key
这样第一次高速排序后数列就变为{1,6,2,4}10{55,12,34,456,66,43,23,65,33,345,61,76,31,43,76}
这样再分别对{1,6,2,4}和{55,12,34,456,66,43,23,65,33,345,61,76,31,43,76} 分别进行高速排序,反复这个步骤,终于使整个数组都是有序的。
详细实现代码为:
private static void QuickSort(int[] R, int low, int high)
{
int pivotLoc = 0;
if(low<high)
{
pivotLoc = Partition(R, low, high);
QuickSort(R, low, pivotLoc - 1);
QuickSort(R, pivotLoc + 1, high);
}
}
private static int Partition(int[] R, int low, int high)
{
int temp = R[low];
while (low < high)
{
while (low < high && temp <= R[high])
{
high--;
}
R[low] = R[high];
while (low < high && temp >= R[low])
{
low++;
}
R[high] = R[low];
}
R[low] = temp;
return low;
}
//高速非递归排序
public static void QuickSort(int[] R, int Low, int High, Stack<int> stack)
{
int low = Low;
int high = High;
int temp = R[low];
while (high > low)
{
while (low < high && temp <= R[high])
{
high--;
}
if (high > low)
{
R[low] = R[high];
R[high] = temp;
}
while (low < high && temp >= R[low])
{
low++;
}
if (high > low)
{
R[high] = R[low];
R[low] = temp;
}
if (low == high)
{
if (Low < low - 1)
{
stack.Push(Low);
stack.Push(low - 1);
}
if (High > low + 1)
{
stack.Push(low + 1);
stack.Push(High);
}
}
}
}
測试代码:
static void Main(string[] args)
{
int[] arry = new int[] { 10, 33, 2, 4, 55, 6, 12, 34, 456, 66, 43, 23, 65, 1, 345, 61, 76, 31, 43, 76 };
Stack<int> s=new Stack<int>();
s.Push(0);
s.Push(arryk.Length - 1);
while (s.Count > 0)
{
int low = s.Pop();
int high = s.Pop();
if (low > high)
{
temp = low;
low = high;
high = temp;
}
QuickSort(arryk, low, high, s);
}
Console.ReadLine();
}
通过对10万条随机数据进行递归和非递归排序后发现,非递归方法的速度是递归方法速度的40倍左右。
5 . 一个无序的数组,怎样通过一个函数取出最大值和最小值,要求时间复杂度最低和空间最少
详细算法例如以下:
private static int[] GetMaxMin(int[] R)
{
int len=R.Length;
int min = R[0];
int max = R[0];
for (int i = 1; i < len;i++ )
{
if (min > R[i])
{
min = R[i];
}
if (max < R[i])
{
max = R[i];
}
}
int[] res = new int[2];
res[0] = min;
res[1] = max;
return res;
}
6 对于已知数组,随机存储一百个数。把奇数放左边。偶数放右边,详细算法例如以下:
private static void SortNumber(int[] R)
{
int high = R.Length - 1;
int low = 0;
int temp = R[low];
while (low < high)
{
while(low<high&&R[high]%2==0)
{
high--;
}
R[low] = R[high];
while (low < high && R[low] % 2 == 1)
{
low++;
}
R[high] = R[low];
}
R[low] = temp;
}
7.二分查找算法
二分查找算法又叫折半查找,长处是比較次数少,查找速度快。平均性能好,缺点是给定的数组必须是有序的,且插入删除困难,因此二分查找使用与不常常变动而又查找频繁的有序表。
首先,假设数组是依照升序的有序表。将表中间位置的元素与给定要查找的元素比較,假设相等。则查找成功。否则利用中间位置将表分为前后两个字表,假设中间位置记录的元素大于给定的查找的数据。在前面的字表中进行查找。否则在后面的字表中进行查找。反复以上过程,直到找到或没有子表为止。
详细实现代码例如以下:
private static int BinarySearch(int[] R, int arg)
{
int low = 0;
int high = R.Length - 1;
while (low < high)
{
int middle = (low + high) / 2;
if (arg == R[middle])
{
return middle;
}
else if (arg < R[middle])
{
high = middle - 1;
}
else
{
low = middle + 1;
}
}
return -1;
}
C#实现(递归和非递归)高速排序和简单排序等一系列排序算法的更多相关文章
- C语言实现 二分查找数组中的Key值(递归和非递归)
基本问题:使用二分查找的方式,对数组内的值进行匹配,如果成功,返回其下标,否则返回 -1.请使用递归和非递归两种方法说明. 非递归代码如下: #include <stdio.h> int ...
- 二叉树之AVL树的平衡实现(递归与非递归)
这篇文章用来复习AVL的平衡操作,分别会介绍其旋转操作的递归与非递归实现,但是最终带有插入示例的版本会以递归呈现. 下面这张图绘制了需要旋转操作的8种情况.(我要给做这张图的兄弟一个赞)后面会给出这八 ...
- 汉诺塔算法的递归与非递归的C以及C++源代码
汉诺塔(又称河内塔)问题其实是印度的一个古老的传说. 开天辟地的神勃拉玛(和中国的盘古差不多的神吧)在一个庙里留下了三根金刚石的棒,第一根上面套着64个圆的金片,最大的一个在底下,其余一个比一 个小, ...
- 数据结构二叉树的递归与非递归遍历之java,javascript,php实现可编译(1)java
前一段时间,学习数据结构的各种算法,概念不难理解,只是被C++的指针给弄的犯糊涂,于是用java,web,javascript,分别去实现数据结构的各种算法. 二叉树的遍历,本分享只是以二叉树中的先序 ...
- C实现二叉树(模块化集成,遍历的递归与非递归实现)
C实现二叉树模块化集成 实验源码介绍(源代码的总体介绍):header.h : 头文件链栈,循环队列,二叉树的结构声明和相关函数的声明.LinkStack.c : 链栈的相关操作函数定义.Queue. ...
- 二叉树3种递归和非递归遍历(Java)
import java.util.Stack; //二叉树3种递归和非递归遍历(Java) public class Traverse { /******************一二进制树的定义*** ...
- 简单迷宫算法(递归与非递归C++实现)
假定迷宫如下:1代表墙,0代表道路,起点在(1,1),终点(11,9)(PS:下标从0开始计算). 现在寻求一条路径能从起点到达终点(非最短). 有两种解法:递归与非递归. 递归算法思路: 要用递归, ...
- JAVA递归、非递归遍历二叉树(转)
原文链接: JAVA递归.非递归遍历二叉树 import java.util.Stack; import java.util.HashMap; public class BinTree { priva ...
- java扫描文件夹下面的所有文件(递归与非递归实现)
java中扫描指定文件夹下面的所有文件扫描一个文件夹下面的所有文件,因为文件夹的层数没有限制可能多达几十层几百层,通常会采用两种方式来遍历指定文件夹下面的所有文件.递归方式非递归方式(采用队列或者栈实 ...
随机推荐
- (3)unity3d 地形
在Hierarchy(层次) 建一个Terrain(地形) Terrain属性按钮 第一个按钮:抬升与下陷地面.单击抬升地形,同时按住shift下陷地形 第二个按钮:绘制高度.同时按住shift绘制等 ...
- [转载][FPGA]有限状态机FSM学习笔记(二)
1. Mealy和Moore状态机的互换 对于给定的时序逻辑功能,可以用Mealy机实现,也可以用Moore机实现.根据Moore机比Mealy机输出落后一个周期的特性,可以实现两种状态机之间的转换. ...
- Jenkins自动化部署入门(一)
开始使用 Jenkins 这一段时间,技术总监为了减少测试环境每次提交新增接口都要部署项目的时间,搞了一个jenkins持续集成github.docker,这样只要每次push代码都会自动部署,确实节 ...
- PyTorch学习笔记之计算图
1. **args, **kwargs的区别 def build_vocab(self, *args, **kwargs): counter = Counter() sources = [] for ...
- Maven的构建配置文件(Build Profiles)
在命令行使用构建配置文件时,是-P,比如:mvn -Pinput 注意:这里的构建配置文件并不是一个真正的文件,而是通过指定参数来做特定的事. 以下内容引用自https://ayayui.gitboo ...
- Android Base64转图片
最近做一个项目里面有关于图片展示的需求,但是任性的后台跟我说没有图片服务器,只能给我base64让我自己转成图片,好吧,我忍,转就转吧.. 首先第一步咱还是谦虚点上百度查查别人咋转的,结果似乎各位码友 ...
- Segmentation fault(core dumped) 调试
ReadingList: https://mytechrants.wordpress.com/2009/05/22/debugging-a-segmentation-fault-using-gdb/ ...
- Free Pascal 的安装
Free Pascal 的安装 https://www.cnblogs.com/cnssc/p/6110492.html https://wenku.baidu.com/view/ee80cc8eed ...
- poj 1651 Multiplication Puzzle【区间DP】
题目链接:http://poj.org/problem? id=1651 题意:初使ans=0,每次消去一个值,位置在pos(pos!=1 && pos !=n) 同一时候ans+=a ...
- HDMI各版本对比
转:一文看懂从HDMI1.0到HDMI2.1的历代规格变化 hdmi HDMI详解 https://blog.csdn.net/xubin341719/article/details/7713450 ...