-
冒泡排序
冒泡排序算法(Bubble Sort)是一种流行但低效的排序算法。它的原理是反复比较待排序数组中所有相邻的两个数据,使他们按照升序(或降序)排列。当待排序数组中所有相邻数据都比较过一次之后,待排序数组中最小(或最大)的数据会被逐步交换到第一位,就像气泡从水底慢慢升到水面一样,故名“冒泡排序算法”。
注意:冒泡排序考数组和for理解,主要面试用
int[] nums={9,8,7,6,5,4,3,2,1,0}; 0 1 2 3 4 5 6 7 8 9
第一趟比较:8 7 6 5 4 3 2 1 0 9 交换了9次 i=0 j=nums.Length-1-i
第二趟比较:7 6 5 4 3 2 1 0 8 9 交换了8次 i=1 j=nums.Length-1-i
第三趟比较:6 5 4 3 2 1 0 7 8 9 交换了7次 i=2 j=nums.Length-1-i
第四趟比较:5 4 3 2 1 0 6 7 8 9 交换了6次 i=3 j=nums.Length-1-i
第五趟比较:4 3 2 1 0 5 6 7 8 9 交换了5次
第六趟比较:3 2 1 0 4 5 6 7 8 9 交换了4次
第七趟比较:2 1 0 3 4 5 6 7 8 9 交换了3次
第八趟比较:1 0 2 3 4 5 6 7 8 9 交换了2次
第九趟比较:0 1 2 3 4 5 6 7 8 9 交换了1次
//冒泡排序
int test = 0;//定义一个中间变量,用来交换值
int[] arr = {9,8,7,6,5,4,3,2,1,0};//定义一个无序数组,用来排序
for (int i = 0; i < arr.Length-1; i++)//我们外层循环需要循环n-1次
{
for (int j = 0; j < arr.Length-1-i; j++)
{
if (arr[j]>arr[j+1])//判断两个值大小是否要交换值
{
//如果数组第二个数小于前一个数,那么把第二个小的数先存放在 test中
test = arr[j + 1];
arr[j + 1] = arr[j];//把前一个大的数放到后面
arr[j] = test;//再把我们存放在test中的小的数放到前面
}
}
}
1 冒泡算法的最坏情况的时间复杂度为O(n^2),最佳情况下的时间复杂度为O(n).
2 冒泡排序也是一种原址排序算法,所以其空间复杂度为O(1)。
3 冒泡排序算法是稳定的。冒泡排序算法只涉及到相邻两个数据的比较,如果相邻两个数的值相等,并不会发生交换。故,排序前后,相同值的相对位置不会改变。 -
选择排序
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
class Program
{
static void Main(string[] args)
{
int[] arr = { 15, 0, 10, 50, 55, 35, 15, 20 }; //待排序数组
SelectSort(arr); //调用选择排序函数
}
private static void SelectSort(int[] arr)
{
int temp = 0;
for (int i = 0; i < arr.Length - 1; i++)
{
int minVal = arr[i]; //假设 i 下标就是最小的数
int minIndex = i; //记录我认为最小的数的下标
for (int j = i + 1; j < arr.Length; j++) //这里只是找出这一趟最小的数值并记录下它的下标
{
//说明我们认为的最小值,不是最小
if (minVal > arr[j]) //这里大于号是升序(大于是找出最小值) 小于是降序(小于是找出最大值)
{
minVal = arr[j]; //更新这趟最小(或最大)的值 (上面要拿这个数来跟后面的数继续做比较)
minIndex = j; //记下它的下标
}
}
//最后把最小的数与第一的位置交换
temp = arr[i]; //把第一个原先认为是最小值的数,临时保存起来
arr[i] = arr[minIndex]; //把最终我们找到的最小值赋给这一趟的比较的第一个位置
arr[minIndex] = temp; //把原先保存好临时数值放回这个数组的空地方, 保证数组的完整性
}
foreach (int item in arr){//控制台输出
Console.WriteLine(“C#遍历:{0}”, item);
}
}
}
1 选择算法的最坏情况的时间复杂度为O(n2),平均时间复杂度为O(n2).
2 选择排序其空间复杂度为O(1)。
3 选择排序算法是稳定的。
3,直接插入排序
算法思路
⒈ 从第一个元素开始,该元素可以认为已经被排序
⒉ 取出下一个元素,在已经排序的元素序列中从后向前扫描
⒊ 如果该元素(已排序)大于新元素,将该元素移到下一位置
⒋ 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
⒌ 将新元素插入到下一位置中
⒍ 重复步骤2~5
class Program{
static void InsertSort(int[] dataArray)
{
for (int i = 1; i < dataArray.Length; i++) //从数组拿第二个值dataArray[1]和dataArray[0]比较大小,循环至整个数组排好序
{
bool isInsert = false; //标志,判断是否插过了
int iValue = dataArray[i]; //保存当前需要比对的值dataArray[i] 为 iValue,防止移动数据时被覆盖
for (int j = i - 1; j >= 0; j–) // 将dataArray[i]和它前面的的所有值作比较
{
if(dataArray[j] > iValue) //如果 当前遍历位置的值 dataArray[j] > iValue
{
dataArray[j + 1] = dataArray[j]; //就把 当前遍历位置的值 dataArray[j] 向后移动一位
}
else //如果 当前遍历位置的值 dataArray[j] < iValue
{
dataArray[j + 1] = iValue; //就把 iValue 放到 dataArray[j] 后面 即 dataArray[j + 1]位置
isInsert = true;
break; //一定要记得加break,否则,会插很多次,值会覆盖混乱
}
}
if (!isInsert) //经过循环,标志false显示未被插入,证明iValue是比它前面的值都小,故将其放入数组0号位置
{
dataArray[0] = iValue;
}
}
}
static void Main(string[] args)
{
int[] dataArray = new int[] { 1, 5, 3, 2, 7, 9, 4, 6, 8};
InsertSort(dataArray);
foreach(var temp in dataArray)
{
Console.WriteLine(temp);
}
Console.ReadKey();
}
}
1 直接插入算法的最坏情况的时间复杂度为O(n2),平均时间复杂度为O(n2).
2 直接插入排序其空间复杂度为O(1)。
3 直接插入排序算法是稳定的。
4,快速排序
快速排序是几种排序方法中效率较高,因此经常被采用,采用快速排序思想----分治法
原理:快速排序法是采用递归的方式对待排序的数列进行若干次的操作,每次操作使得被操作的数列部分以某个元素为分界值分成两部分,一部分小于该分界值,另一部分大于该分界值.该分界值一般被称为"枢轴". 一般先以左边第一个数作为分界值,将数列按该分界值分成左右两部分,左边部分小于该分界值,右边部分大于该分界值,然后再对左右两部分做重复的操作,直到最后完成排序。
1 快速排序算法的最坏情况的时间复杂度为O(n2),平均时间复杂度为O(n*log2n).
2 快速排序其空间复杂度为O(log2n)~O(n)。
3 快速排序算法是不稳定。
该方法的基本思想是:
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
假设我们要对数组Array 6 7 2 1 9 4 3 10 5 8排序,先在序列中找任意一个数(此例取第一个)作为基准数(就是一界限,大于此数放序列的右边,小于或等于放左边)
下标 0 1 2 3 4 5 6 7 8 9
值 6 7 2 1 9 4 3 10 5 8
初始化:i=0,j=9,基准数 X=6,从j开始往前找一个小于或等于X的数。
当j=8时,Array [0] = Array[8](i++),数组变为:
下标 0 1 2 3 4 5 6 7 8 9
值 5 7 2 1 9 4 3 10 5 8
当i=1时,Array[8]= Array1,数组变为:从i开始往后找一个比X大的数,
下标 0 1 2 3 4 5 6 7 8 9
值 5 7 2 1 9 4 3 10 7 8
当j=6时,Array[1]= Array6,数组变为:从j开始往前找一个小于或等于X的数,
下标 0 1 2 3 4 5 6 7 8 9
值 5 3 2 1 9 4 3 10 7 8
当i=4时,Array[6]= Array[4] (j–),数组变为:从i开始往后找一个大于X的数,
下标 0 1 2 3 4 5 6 7 8 9
值 5 3 2 1 9 4 9 10 7 8
当j=5时,Array[4]= Array [5] (i++),数组变为:从j开始往前找一个小于或等于X的数
下标 0 1 2 3 4 5 6 7 8 9
值 5 3 2 1 4 4 9 10 7 8
当ij5时,停止循环,将基准数填入,Array[5]=X,数组变为:
下标 0 1 2 3 4 5 6 7 8 9
值 5 3 2 1 4 6 9 10 7 8
C#代码实现:此次循环结束后,可以看出,Array[5]左边的数据都比它小,右边的数都比它大,因此再对Array [0…4] 和Array [6…9]重复上述步骤即可(递归调用)。
static void Main(string[] args){
int[] array = new[] {6, 7, 2, 1, 9, 4, 3, 10, 5, 8};
Sort(array, 0, array.Length - 1);
foreach (int item in array)
{
Console.Write(item + " ");
}
}
/// 排序
/// 要排序的数组
/// 下标开始位置,向右查找
/// 下标开始位置,向左查找
public static void Sort(int[] array, int low, int high)
{
if (low >= high) return;
//完成一次单元排序
int index = SortUnit(array, low, high);
//递归调用,对左边部分的数组进行单元排序
Sort(array, low, index - 1);
//递归调用,对右边部分的数组进行单元排序
Sort(array, index + 1, high);
}
/// 单元排序
/// 要排序的数组
/// 下标开始位置,向右查找
/// 下标开始位置,向右查找
/// 每次单元排序的停止下标
public static int SortUnit(int[] array, int low, int high){
int key = array[low];//基准数
while (low < high)
{
//从high往前找小于或等于key的值
while (low < high && array[high] > key)
high–;
//比key小开等的放左边
array[low] = array[high];
//从low往后找大于key的值
while (low < high && array[low] <= key)
low++;
//比key大的放右边
array[high] = array[low];
}
//结束循环时,此时low等于high,左边都小于或等于key,右边都大于key。将key放在游标当前位置。
array[low] = key;
return high;
}
5,希尔排序
希尔(Shell)排序又称为缩小增量排序,它是一种插入排序。它是直接插入排序算法的一种威力加强版。
基本思想:
把记录按步长 gap 分组,对每组记录采用直接插入排序方法进行排序。
随着步长逐渐减小,所分成的组包含的记录越来越多,当步长的值减小到 1 时,整个数据合成为一组,构成一组有序记录,则完成排序。
操作步骤:
初始时,有一个大小为 10 的无序序列。
(1)在第一趟排序中,令增量d = N / 2 = 5,即相隔距离为 5 的元素组成一组,可以分为 5 组。
(2)按照直接插入排序的方法对每个组进行排序。
(3)在第二趟排序中,我们把上次的 d 缩小一半,即 d= d / 2 = 2 (取整数)。这样每相隔距离为 2 的元素组成一组,可以分为 2 组。
(4)按照直接插入排序的方法对每个组进行排序。
(5)在第三趟排序中,再次把 d 缩小一半,即d = d / 2 = 1。 这样相隔距离为 1 的元素组成一组,即只有一组。
(6)按照直接插入排序的方法对每个组进行排序。此时,排序已经结束。
1 希尔排序算法的最坏情况的时间复杂度为O(n1.5),平均时间复杂度为O(n*log2n)
2 希尔排序其空间复杂度为O(1)。
3 希尔排序算法是不稳定。
static void Main(string[] args){
int[] arr = new int[] { 9, 1, 2, 5, 7, 4, 8, 6, 3, 5 };
ShellSort(arr);
Console.ReadKey();
}
public static void ShellSort(int[] array){
int gap = array.Length / 2;
while (1 <= gap){
// 把距离为 gap 的元素编为一个组,扫描所有组
//gap=5, i=5,6,7,8,9
//gap=2, i=2,3,4,5,6,7,8,9
for (int i = gap; i < array.Length; i++){
int j = 0;
int temp = array[i];//
// 对距离为 gap 的元素组进行排序
//j = 0,1,2,3,4 j = j - gap -5,-4,-3,-2,-1
//j = 0,1,2,3,4,5,6,7 j = j - gap -2,-1,0,1,2,3,4,5
for (j = i - gap; j >= 0; j = j - gap)
{
If( temp < array[j]){
array[j + gap] = array[j];
}
}
array[j + gap] = temp;
}
foreach (int n in array){
Console.Write("{0} ", n);
}
gap = gap / 2; // 减小增量
}
}