午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

算法系列15天速成

 復(fù)雜網(wǎng)絡(luò)621 2015-09-15

首先感謝朋友們對第一篇文章的鼎力支持,感動中....... 

 

今天說的是選擇排序,包括“直接選擇排序”和“堆排序”。

 

話說上次“冒泡排序”被快排虐了,而且“快排”贏得了內(nèi)庫的重用,眾兄弟自然眼紅,非要找快排一比高下。

這不今天就來了兩兄弟找快排算賬。

 

1.直接選擇排序: 

先上圖:

 

說實話,直接選擇排序最類似于人的本能思想,比如把大小不一的玩具讓三歲小毛孩對大小排個序,

那小孩首先會在這么多玩具中找到最小的放在第一位,然后找到次小的放在第二位,以此類推。。。。。。

,小孩子多聰明啊,這么小就知道了直接選擇排序。羨慕中........

 

對的,小孩子給我們上了一課,

第一步: 我們拿80作為參照物(base),在80后面找到一個最小數(shù)20,然后將80跟20交換。

第二步:  第一位數(shù)已經(jīng)是最小數(shù)字了,然后我們推進一步在30后面找一位最小數(shù),發(fā)現(xiàn)自己最小,不用交換。

第三步:........

最后我們排序完畢。大功告成。

 

既然是來挑戰(zhàn)的,那就5局3勝制。

復(fù)制代碼
 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using System.Diagnostics;
7
8 namespace SelectionSort
9 {
10 public class Program
11 {
12 static void Main(string[] args)
13 {
14 //5次比較
15 for (int i = 1; i <= 5; i++)
16 {
17 List<int> list = new List<int>();
18
19 //插入2w個隨機數(shù)到數(shù)組中
20 for (int j = 0; j < 20000; j++)
21 {
22 Thread.Sleep(1);
23 list.Add(new Random((int)DateTime.Now.Ticks).Next(1000, 1000000));
24 }
25
26 Console.WriteLine("\n第" + i + "次比較:");
27
28 Stopwatch watch = new Stopwatch();
29
30 watch.Start();
31 var result = list.OrderBy(single => single).ToList();
32 watch.Stop();
33
34 Console.WriteLine("\n快速排序耗費時間:" + watch.ElapsedMilliseconds);
35 Console.WriteLine("輸出前十個數(shù):" + string.Join(",", result.Take(10).ToList()));
36
37 watch.Start();
38 result = SelectionSort(list);
39 watch.Stop();
40
41 Console.WriteLine("\n直接選擇排序耗費時間:" + watch.ElapsedMilliseconds);
42 Console.WriteLine("輸出前十個數(shù):" + string.Join(",", list.Take(10).ToList()));
43
44 }
45 }
46
47 //選擇排序
48 static List<int> SelectionSort(List<int> list)
49 {
50 //要遍歷的次數(shù)
51 for (int i = 0; i < list.Count - 1; i++)
52 {
53 //假設(shè)tempIndex的下標的值最小
54 int tempIndex = i;
55
56 for (int j = i + 1; j < list.Count; j++)
57 {
58 //如果tempIndex下標的值大于j下標的值,則記錄較小值下標j
59 if (list[tempIndex] > list[j])
60 tempIndex = j;
61 }
62
63 //最后將假想最小值跟真的最小值進行交換
64 var tempData = list[tempIndex];
65 list[tempIndex] = list[i];
66 list[i] = tempData;
67 }
68 return list;
69 }
70 }
71 }
復(fù)制代碼

比賽結(jié)果公布:

 

堆排序:

要知道堆排序,首先要了解一下二叉樹的模型。

下圖就是一顆二叉樹,具體的情況我后續(xù)會分享的。

那么堆排序中有兩種情況(看上圖理解):

    大根堆:  就是說父節(jié)點要比左右孩子都要大。

    小根堆:  就是說父節(jié)點要比左右孩子都要小。

 

那么要實現(xiàn)堆排序,必須要做兩件事情:

   第一:構(gòu)建大根堆。

           首先上圖:

           

首先這是一個無序的堆,那么我們怎樣才能構(gòu)建大根堆呢?

     第一步: 首先我們發(fā)現(xiàn),這個堆中有2個父節(jié)點(2,,3);

     第二步: 比較2這個父節(jié)點的兩個孩子(4,5),發(fā)現(xiàn)5大。

     第三步: 然后將較大的右孩子(5)跟父節(jié)點(2)進行交換,至此3的左孩子堆構(gòu)建完畢,

                 如圖:

                         

     第四步: 比較第二個父節(jié)點(3)下面的左右孩子(5,1),發(fā)現(xiàn)左孩子5大。

     第五步: 然后父節(jié)點(3)與左孩子(5)進行交換,注意,交換后,堆可能會遭到破壞,

                 必須按照以上的步驟一,步驟二,步驟三進行重新構(gòu)造堆。

           

最后構(gòu)造的堆如下:

                 

 

   第二:輸出大根堆。

             至此,我們把大根堆構(gòu)造出來了,那怎么輸出呢?我們做大根堆的目的就是要找出最大值,

         那么我們將堆頂(5)與堆尾(2)進行交換,然后將(5)剔除根堆,由于堆頂現(xiàn)在是(2),

         所以破壞了根堆,必須重新構(gòu)造,構(gòu)造完之后又會出現(xiàn)最大值,再次交換和剔除,最后也就是俺們

         要的效果了,

 

 

發(fā)現(xiàn)自己兄弟被別人狂毆,,堆排序再也坐不住了,決定要和快排干一場。

同樣,快排也不甘示弱,誰怕誰?

 

復(fù)制代碼
  1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using System.Diagnostics;
7
8 namespace HeapSort
9 {
10 public class Program
11 {
12 static void Main(string[] args)
13 {
14 //5次比較
15 for (int j = 1; j <= 5; j++)
16 {
17 List<int> list = new List<int>();
18
19 //插入2w個數(shù)字
20 for (int i = 0; i < 20000; i++)
21 {
22 Thread.Sleep(1);
23 list.Add(new Random((int)DateTime.Now.Ticks).Next(1000, 100000));
24 }
25
26 Console.WriteLine("\n第" + j + "次比較:");
27
28 Stopwatch watch = new Stopwatch();
29 watch.Start();
30 var result = list.OrderBy(single => single).ToList();
31 watch.Stop();
32 Console.WriteLine("\n快速排序耗費時間:" + watch.ElapsedMilliseconds);
33 Console.WriteLine("輸出前十個數(shù)" + string.Join(",", result.Take(10).ToList()));
34
35 watch = new Stopwatch();
36 watch.Start();
37 HeapSort(list);
38 watch.Stop();
39 Console.WriteLine("\n堆排序耗費時間:" + watch.ElapsedMilliseconds);
40 Console.WriteLine("輸出前十個數(shù)" + string.Join(",", list.Take(10).ToList()));
41 }
42
43 }
44
45 ///<summary>
46 /// 構(gòu)建堆
47 ///</summary>
48 ///<param name="list">待排序的集合</param>
49 ///<param name="parent">父節(jié)點</param>
50 ///<param name="length">輸出根堆時剔除最大值使用</param>
51 static void HeapAdjust(List<int> list, int parent, int length)
52 {
53 //temp保存當(dāng)前父節(jié)點
54 int temp = list[parent];
55
56 //得到左孩子(這可是二叉樹的定義,大家看圖也可知道)
57 int child = 2 * parent + 1;
58
59 while (child < length)
60 {
61 //如果parent有右孩子,則要判斷左孩子是否小于右孩子
62 if (child + 1 < length && list[child] < list[child + 1])
63 child++;
64
65 //父親節(jié)點大于子節(jié)點,就不用做交換
66 if (temp >= list[child])
67 break;
68
69 //將較大子節(jié)點的值賦給父親節(jié)點
70 list[parent] = list[child];
71
72 //然后將子節(jié)點做為父親節(jié)點,已防止是否破壞根堆時重新構(gòu)造
73 parent = child;
74
75 //找到該父親節(jié)點較小的左孩子節(jié)點
76 child = 2 * parent + 1;
77 }
78 //最后將temp值賦給較大的子節(jié)點,以形成兩值交換
79 list[parent] = temp;
80 }
81
82 ///<summary>
83 /// 堆排序
84 ///</summary>
85 ///<param name="list"></param>
86 public static void HeapSort(List<int> list)
87 {
88 //list.Count/2-1:就是堆中父節(jié)點的個數(shù)
89 for (int i = list.Count / 2 - 1; i >= 0; i--)
90 {
91 HeapAdjust(list, i, list.Count);
92 }
93
94 //最后輸出堆元素
95 for (int i = list.Count - 1; i > 0; i--)
96 {
97 //堆頂與當(dāng)前堆的第i個元素進行值對調(diào)
98 int temp = list[0];
99 list[0] = list[i];
100 list[i] = temp;
101
102 //因為兩值交換,可能破壞根堆,所以必須重新構(gòu)造
103 HeapAdjust(list, 0, i);
104 }
105 }
106 }
107 }
復(fù)制代碼

結(jié)果公布:

 

堆排序此時心里很尷尬,雙雙被KO,心里想,一定要撈回面子,一定要贏,

 

于是堆排序提出了求“前K大問題”。(就是在海量數(shù)據(jù)中找出前幾大的數(shù)據(jù)),

快排一口答應(yīng),小意思,沒問題。

雙方商定,在2w隨機數(shù)中找出前10大的數(shù):

復(fù)制代碼
  1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using System.Diagnostics;
7
8 namespace QuickSort
9 {
10 public class Program
11 {
12 static void Main(string[] args)
13 {
14 //5此比較
15 for (int j = 1; j <= 5; j++)
16 {
17 List<int> list = new List<int>();
18
19 for (int i = 0; i < 20000; i++)
20 {
21 Thread.Sleep(1);
22 list.Add(new Random((int)DateTime.Now.Ticks).Next(1000, 100000));
23 }
24
25 Console.WriteLine("\n第" + j + "次比較:");
26
27 Stopwatch watch = new Stopwatch();
28 watch.Start();
29 var result = list.OrderByDescending(single => single).Take(10).ToList();
30 watch.Stop();
31 Console.WriteLine("\n快速排序求前K大耗費時間:" + watch.ElapsedMilliseconds);
32 Console.WriteLine("輸出前十個數(shù):" + string.Join(",", result.Take(10).ToList()));
33
34 watch = new Stopwatch();
35 watch.Start();
36 result = HeapSort(list, 10);
37 watch.Stop();
38 Console.WriteLine("\n堆排序求前K大耗費時間:" + watch.ElapsedMilliseconds);
39 Console.WriteLine("輸出前十個數(shù):" + string.Join(",", list.Take(10).ToList()));
40 }
41
42 }
43
44 ///<summary>
45 /// 構(gòu)建堆
46 ///</summary>
47 ///<param name="list">待排序的集合</param>
48 ///<param name="parent">父節(jié)點</param>
49 ///<param name="length">輸出根堆時剔除最大值使用</param>
50 static void HeapAdjust(List<int> list, int parent, int length)
51 {
52 //temp保存當(dāng)前父節(jié)點
53 int temp = list[parent];
54
55 //得到左孩子(這可是二叉樹的定義哇)
56 int child = 2 * parent + 1;
57
58 while (child < length)
59 {
60 //如果parent有右孩子,則要判斷左孩子是否小于右孩子
61 if (child + 1 < length && list[child] < list[child + 1])
62 child++;
63
64 //父節(jié)點大于子節(jié)點,不用做交換
65 if (temp >= list[child])
66 break;
67
68 //將較大子節(jié)點的值賦給父親節(jié)點
69 list[parent] = list[child];
70
71 //然后將子節(jié)點做為父親節(jié)點,已防止是否破壞根堆時重新構(gòu)造
72 parent = child;
73
74 //找到該父節(jié)點左孩子節(jié)點
75 child = 2 * parent + 1;
76 }
77 //最后將temp值賦給較大的子節(jié)點,以形成兩值交換
78 list[parent] = temp;
79 }
80
81 ///<summary>
82 /// 堆排序
83 ///</summary>
84 ///<param name="list">待排序的集合</param>
85 ///<param name="top">前K大</param>
86 ///<returns></returns>
87 public static List<int> HeapSort(List<int> list, int top)
88 {
89 List<int> topNode = new List<int>();
90
91 //list.Count/2-1:就是堆中非葉子節(jié)點的個數(shù)
92 for (int i = list.Count / 2 - 1; i >= 0; i--)
93 {
94 HeapAdjust(list, i, list.Count);
95 }
96
97 //最后輸出堆元素(求前K大)
98 for (int i = list.Count - 1; i >= list.Count - top; i--)
99 {
100 //堆頂與當(dāng)前堆的第i個元素進行值對調(diào)
101 int temp = list[0];
102 list[0] = list[i];
103 list[i] = temp;
104
105 //最大值加入集合
106 topNode.Add(temp);
107
108 //因為順序被打亂,必須重新構(gòu)造堆
109 HeapAdjust(list, 0, i);
110 }
111 return topNode;
112 }
113 }
114 }
復(fù)制代碼

求前K大的輸出結(jié)果:

 

 

最后堆排序趕緊拉著直接選擇排序一路小跑了,因為求前K大問題已經(jīng)不是他原本來的目的。

 

ps: 直接選擇排序的時間復(fù)雜度為:O(n^2)

       堆排序的時間復(fù)雜度:O(NlogN)

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多