7种排序算法

来源:互联网 发布:cms绑定域名 编辑:程序博客网 时间:2024/06/02 00:50

说是复习,与其说是学习更加的准确,毕竟大部分的思想都是忘记了,而且书有弄丢了,所以在网上东拼西凑的找了一下资料,来学习排序算法,

毕竟这个是非常基础而且重要的东西,大部分是使用C#来实现的,有用List的,也有用IList的,总之主要的目的是想了解这些算法背后的编程思想,

这个是非常重要的,毕竟 语言知识工具,算法才是程序的灵魂


1 选择排序:

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法(比如序列[5, 5, 3]第一次就将第一个[5]与[3]交换,导致第一个5挪动到第二个5后面)。

思想:

n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果:

①初始状态:无序区为R[1..n],有序区为空。

②第1趟排序

在无序区R[1..n]中选出关键字最小的记录R[k],将它与无序区的第1个记录R[1]交换,使R[1..1]和R[2..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。

③第i趟排序

第i趟排序开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当前无序区中选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。

通俗的解释

对比数组中前一个元素跟后一个元素的大小,如果后面的元素比前面的元素小则用一个变量k来记住他的位置,接着第二次比较,前面“后一个元素”现变成了“前一个元素”,继续跟他的“后一个元素”进行比较如果后面的元素比他要小则用变量k记住它在数组中的位置(下标),等到循环结束的时候,我们应该找到了最小的那个数的下标了,然后进行判断,如果这个元素的下标不是第一个元素的下标,就让第一个元素跟他交换一下值,这样就找到整个数组中最小的数了。然后找到数组中第二小的数,让他跟数组中第二个元素交换一下值,以此类推。

 /// <summary>        /// 选择排序        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="arr"></param>        static void selection_sort<T>(T[] arr) where T : System.IComparable<T>        {            int i, j, min, len = arr.Length;            T temp;            for (i = 0; i < len - 1; i++)            {                min = i;                for (j = i + 1; j < len; j++)                {                    if (arr[min].CompareTo(arr[j]) > 0)                    {                        min = j;                    }                }                temp = arr[min];                arr[min] = arr[i];                arr[i] = temp;            }        }


2.二分法插入排序:
二分法插入排序是在插入第i个元素时,对前面的0~i-1元素进行折半,先跟他们中间的那个元素比,如果小,则对前半再进行折半,否则对后半进行折半,直到left>right,然后再把第i个元素前1位与目标位置之间的所有元素后移,再把第i个元素放在目标位置上。
/// <summary>        /// 二分法插入排序        /// </summary>        /// <param name="data"></param>        static void InsertSort(int[] data)        {            int i, j;            int count = data.Length;            for (i = 1; i < count; i++)            {                int t = data[i];                for (j = i - 1; j > 0 && data[i] > t; j--)                {                    data[j + 1] = data[j];                }                data[j + 1] = t;            }        }        public static void InsertSortImprovedWithBinarySearch(IList<int> data)        {            int temp;            int tempIndex;            for (int i = 1; i < data.Count; i++)            {                temp = data[i];                tempIndex = BinarySearchForInsertSort(data, 0, i, i);                for (int j = i - 1; j >= tempIndex; j--)                {                    data[j + 1] = data[j];                }                data[tempIndex] = temp;            }        }        public static int BinarySearchForInsertSort(IList<int> data, int low, int high, int key)        {            if (low >= data.Count - 1)                return data.Count - 1;            if (high <= 0)                return 0;            int mid = (low + high) / 2;            if (mid == key) return mid;            if (data[key] > data[mid])            {                if (data[key] < data[mid + 1])                    return mid + 1;                return BinarySearchForInsertSort(data, mid + 1, high, key);            }            else            {                if (mid - 1 < 0) return 0;                if (data[key] > data[mid - 1])                    return mid;                return BinarySearchForInsertSort(data, low, mid - 1, key);            }        }

3。快速排序:
设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。 
private static void QuicklySort(int[] numbers, int left, int right)        {            if (left < right)            {                int middle = numbers[(left + right) / 2];                int i = left - 1;                int j = right + 1;                while (true)                {                    while (numbers[++i] < middle) ;                    while (numbers[--j] > middle) ;                    if (i > j)                        break;                }                Swap(numbers, left, i - 1);                Swap(numbers, j + 1, right);            }        }        private static void Swap(int[] numbers, int i, int j)        {            int number = numbers[i];            numbers[i] = numbers[j];            numbers[j] = number;        }

4。归并排序:
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。

算法描述

编辑
归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
public static List<int> Sort(List<int> list)        {            if (list.Count <= 1)                return list;            int mid = list.Count / 2;            List<int> left = new List<int>();            List<int> right = new List<int>();            for (int i = 0; i < mid; i++)            {                left.Add(list[i]);            }            for (int i = mid; i < list.Count; i++)            {                right.Add(list[i]);            }            left = Sort(left);            right = Sort(right);            return Merge(left, right);        }        private static List<int> Merge(List<int> left, List<int> right)        {            List<int> temp = new List<int>();            while (left.Count > 0 && right.Count > 0)            {                if (left[0] < right[0])                {                    temp.Add(left[0]);                    left.RemoveAt(0);                }                else                {                    temp.Add(right[0]);                    right.RemoveAt(0);                }                if (left.Count > 0)                {                    for (int i = 0; i < left.Count; i++)                    {                        temp.Add(left[i]);                    }                }                if (right.Count > 0)                {                    for (int i = 0; i < right.Count; i++)                    {                        temp.Add(right[i]);                    }                }            }        }

5.堆排序:
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。
 private static void Swap(IList<int> numbers, int i, int j)        {            int number = numbers[i];            numbers[i] = numbers[j];            numbers[j] = number;        }        public static void HeapSort(IList<int> data)        {            BuildMaxHeapify(data);            int j = data.Count;            for (int i = 0; i < j; )            {                Swap(data, i, --j);                if (j - 2 < 0)                {                    break;                }                int k = 0;                while (true)                {                    if (k > (j - 2) / 2) break;                    else                    {                        int temp = k;                        k = ReSortMaxBranch(data, k, 2 * k + 1, 2 * k + 2, j - 1);                        if (temp == k) break;                    }                }            }        }        public static void BuildMaxHeapify(IList<int> data)        {            for (int i = data.Count / 2 - 1; i >= 0; i--)            {                int temp = i;                temp = ReSortMaxBranch(data, i, 2 * i + 1, 2 * i + 2, data.Count - 1);                if (temp != i)                {                    int k = i;                    while (k != temp && temp <= data.Count / 2 - 1)                    {                        k = temp;                        temp = ReSortMaxBranch(data, temp, 2 * temp + 1, 2 * temp + 2, data.Count);                    }                }            }        }        public static int ReSortMaxBranch(IList<int> data, int maxIndex, int left, int right, int lastIndex)        {            int temp;            if (right > lastIndex) temp = left;            else            {                if (data[left] > data[right])                {                    temp = left;                }                else                {                    temp = right;                }            }            if (data[maxIndex] < data[temp])            {                Swap(data, maxIndex, temp);            }            else            {                temp = maxIndex;            }            return temp;        }

6. 希尔排序:

基本思想

编辑
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量
  
=1(
  
<
  
…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
该方法实质上是一种分组插入方法
比较相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素,则进行一次比[2]  较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。
一般的初次取序列的一半为增量,以后每次减半,直到增量为1。
给定实例的shell排序的排序过程
假设待排序文件有10个记录,其关键字分别是:
49,38,65,97,76,13,27,49,55,04。
增量序列的取值依次为:
5,2,1[3] 
希尔排序实例希尔排序实例

 public static void ShellSort(IList<int> data)        {            int temp;            for (int gap = data.Count / 2; gap > 0; gap /= 2)            {                for (int i = dap; i < data.Count; i++)                {                    temp = data[i];                    for (int j = i - gap; j >= 0; j -= gap)                    {                        if (data[j] > temp)                        {                            data[j + gap] = data[j];                            if (j == 0)                            {                                data[j] = temp;                                break;                            }                        }                        else                        {                            data[j + gap] = temp;                            break;                        }                    }                }            }        }

7.桶排序:
public static void BucketSortOnlyUnitDigit(IList<int> data)        {            int[] indexCounter = new int[10];            for (int i = 0; i < data.Count; i++)            {                indexCounter[data[i]]++;            }            int[] indexBegin = new int[10];            for (int i = 1; i < 10; i++)            {                indexBegin[i] = indexBegin[i - 1] + indexBegin[i - 1];            }            IList<int> tempList = NewInstance(data, data.Count);            for (int i = 0; i < data.Count; i++)            {                int number = data[i];                tempList[indexBegin[number]++] = data[i];            }        }


文章中的文字描述摘录自百度百科,算法是自己写的,如果有错,还望指出,谢谢!




0 0
原创粉丝点击