各种排序运行时间比较
以下表格展现各算法的运行时间:
算法 | 最坏情况运行时间 | 平均情况/期望运行时间 |
插入排序 | θ(n2) | θ(n2) |
归并排序 | θ(nlgn) | θ(nlgn) |
堆排序 | O(nlgn) | — |
快速排序 | θ(n2) | θ(nlgn) |
建立一个类,将之前写的各种排序算法纳入其中,Code如下:
class SortMehod { //-----快速排序---- private int Partition(List<int> array, int p, int r) { int x = array[r], temp; int i = p - 1; //类似于一个指示,在该指示左边的值均小于x for (int j = p; j < r; j++) { if (array[j] <= x) //遇到比x小的,放到i的下一位去 { i++; temp = array[i]; array[i] = array[j]; array[j] = temp; } } array[r] = array[i + 1]; array[i + 1] = x; return i + 1; } public void QuickSort(List<int> array, int p, int r) { int q; if (p < r) //进行递归的条件 { q = Partition(array, p, r); QuickSort(array, p, q - 1); QuickSort(array, q + 1, r); } } //-----归并排序---- private void Merge(List<int> array, int p, int q, int r) { int len1 = q - p + 1, n1 = 0; //用于临时存储两边元素的数组的参数 int len2 = r - q, n2 = 0; int[] arr1 = new int[len1]; //建立两个临时数组,用于储存数组值 int[] arr2 = new int[len2]; for (int i = 0; i < len1; i++) //将array值拷贝到临时存放数组 arr1[i] = array[p + i]; for (int j = 0; j < len2; j++) arr2[j] = array[j + q + 1]; for (int k = p; k < r + 1; k++) //将两个数组中的值按升序放回到array数组中 { if (arr1[n1]<arr2[n2]) array[k] = arr1[n1++]; else array[k] = arr2[n2++]; if (n1 == len1) //此处为arr1数组已全部取完后的处理情况 { for (int m = k + 1; m < r + 1; m++) array[m] = arr2[n2++]; break; } if (n2 == len2) { for (int m = k + 1; m < r + 1; m++) array[m] = arr1[n1++]; break; } } } public void MergeSort(List<int> array, int p, int r) { if (p < r) { int q = (p + r) / 2; MergeSort(array, p, q); MergeSort(array, q + 1, r); Merge(array, p, q, r); } } //----插入排序----- public void InsertSort(List<int> array) { for (int i = 1; i < array.Count; i++) //将第i个数插入已排好序的[0...i-1]中 { int key = array[i]; int position = i; //用于记录将要插入的位置 for (int j = i; j >= 0; j--) //将要前面数与要插入数进行比较,如果比key大,往后移一位 { if (array[j] > key) //由于int实现了IComparable接口 { array[j + 1] = array[j]; position = j; } } array[position] = key; } } //----堆排序---- private void MaxHeapify(List<int> array, int i, int length) //此处加个length是为了堆排序时取出最大下标 { int largest = i; int left = 2 * i + 1, right = 2 * i + 2; if (left < length && array[left] > array[i]) //找出i,2i+1,2i+2中最大那个值的下标 largest = left; if (right < length && array[right] > array[largest]) largest = right; if (largest != i) { int temp = array[i]; //将最大值放入i中 array[i] = array[largest]; array[largest] = temp; MaxHeapify(array, largest, length); //将被改动那个下标再次递归进行维护 } } private void BuildMaxHeap(List<int> array) { for (int i = (array.Count - 2) / 2; i >= 0; i--) //此处i从(n-2)/2开始,因为没有子节点的节点无需进行"维护" MaxHeapify(array, i, array.Count); } public void HeapSort(List<int> array) { BuildMaxHeap(array); for (int i = array.Count - 1; i > 0; i--) //每次将堆得根与最大下标的值互换,并将最大下标"剔除" { int temp = array[i]; array[i] = array[0]; array[0] = temp; MaxHeapify(array, 0, i); } } }
并利用如下测试代码进行测试(其中通过改变N的大小,来改变排序的量)
class Program { static void Main(string[] args) { int N = 100000; Console.WriteLine("几种排序算法的性能比较:"); Random rnd=new Random(); SortMehod sort = new SortMehod(); Stopwatch sw = new Stopwatch(); //用于计时的代码 List<int> arr1 = new List<int>(); List<int> arr2 = new List<int>(); List<int> arr3 = new List<int>(); List<int> arr4 = new List<int>(); List<int> arr5 = new List<int>(); for(int i=0;i<N;i++) arr1.Add(rnd.Next(0,N)); foreach(int a in arr1) { arr2.Add(a); arr3.Add(a); arr4.Add(a); arr5.Add(a); } Console.Write("归并排序耗时: "); sw.Reset(); sw.Start(); sort.MergeSort(arr2,0,arr2.Count-1); sw.Stop(); TimeSpan ts = sw.Elapsed; Console.Write("{0} ms", ts.TotalMilliseconds); Console.WriteLine(); Console.Write("堆排序耗时: "); sw.Reset(); sw.Start(); sort.HeapSort(arr3); sw.Stop(); ts = sw.Elapsed; Console.Write("{0} ms", ts.TotalMilliseconds); Console.WriteLine(); Console.Write("快速排序耗时: "); sw.Reset(); sw.Start(); sort.QuickSort(arr4,0,arr4.Count-1); sw.Stop(); ts = sw.Elapsed; Console.Write("{0} ms", ts.TotalMilliseconds); Console.WriteLine(); Console.Write("自带排序耗时: "); sw.Reset(); sw.Start(); arr5.Sort(); sw.Stop(); ts = sw.Elapsed; Console.Write("{0} ms", ts.TotalMilliseconds); Console.WriteLine(); Console.Write("插入排序耗时: "); sw.Reset(); sw.Start(); sort.InsertSort(arr1); sw.Stop(); ts = sw.Elapsed; Console.Write("{0} ms", ts.TotalMilliseconds); Console.WriteLine(); Console.ReadKey(); } }
以下比较不同N情况下不同算法,以及List自带的Sort的运行时间:
①N=1000(测试四次的结果如下)
N=1000 | ||||
归并排序 | 1.9566 | 1.6052 | 1.3499 | 1.5165 |
堆排序 | 2.1112 | 2.0532 | 1.6554 | 1.8805 |
快速排序 | 1.214 | 1.4247 | 1.077 | 1.1416 |
自带排序 | 0.1171 | 0.1153 | 0.1165 | 0.1122 |
插入排序 | 7.9769 | 9.9052 | 8.8179 | 9.5882 |
②N=10000(测试四次的结果如下)
N=10000 | ||||
归并排序 | 7.5157 | 8.2317 | 8.2776 | 8.4587 |
堆排序 | 12.573 | 14.3051 | 14.4609 | 13.5613 |
快速排序 | 4.8044 | 5.3743 | 5.2867 | 5.7667 |
自带排序 | 0.8953 | 1.1639 | 1.1706 | 0.8995 |
插入排序 | 686.8003 | 773.3787 | 797.0869 | 691.3083 |
③N=100000(测试四次的结果如下)
N=100000 | ||||
归并排序 | 65.0672 | 67.563 | 68.7529 | 65.7621 |
堆排序 | 171.2636 | 175.288 | 171.3451 | 179.607 |
快速排序 | 57.0721 | 52.1234 | 53.8658 | 54.4496 |
自带排序 | 12.3026 | 11.6844 | 11.1253 | 10.4057 |
插入排序 | 63958.22 | 62566.23 | 62345.36 | 62768.1 |
④N=1000000(插入明显掉队,踢踢踢)
N=1000000 | ||||
归并排序 | 768.613 | 751.9485 | 747.2539 | 758.8756 |
堆排序 | 2137.371 | 1682.949 | 1660.753 | 1701.584 |
快速排序 | 681.6198 | 635.0487 | 618.8926 | 634.7716 |
自带排序 | 129.4649 | 133.6034 | 143.659 | 130.8897 |
⑤N=10000000(插入明显掉队,踢踢踢)
N=10000000 | ||||
归并排序 | 8052.816 | 8128.458 | 8020.946 | 8012.873 |
堆排序 | 21705.06 | 22002.53 | 21969.92 | 21700.73 |
快速排序 | 7168.563 | 7285.977 | 7214.105 | 7078.338 |
自带排序 | 1500.894 | 1545.198 | 1536.903 | 1516.837 |
由以上可以明显看到 自带排序(据说也是快速排序,为毛快那么多!不科学)>快速排序>归并排序>堆排序>插入排序
自带排序的源码怎么看呢?以及自带排序为什么比快速排序快呢?(希望知道的朋友告知一下)
时间: 2024-10-15 18:32:45