• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 70  文章 - 160  trackbacks - 0

            公告:
            知識共享許可協議
            本博客采用知識共享署名 2.5 中國大陸許可協議進行許可。本博客版權歸作者所有,歡迎轉載,但未經作者同意不得隨機刪除文章任何內容,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。 具體操作方式可參考此處。如您有任何疑問或者授權方面的協商,請給我留言。

            常用鏈接

            留言簿(8)

            隨筆檔案

            文章檔案

            搜索

            •  

            積分與排名

            • 積分 - 179004
            • 排名 - 147

            最新評論

            閱讀排行榜

            評論排行榜

            建議先看看前言:http://www.shnenglu.com/tanky-woo/archive/2011/04/09/143794.html

            本章內容頗多,所以我分三篇來寫,這一篇是關于一些基本的概念和選擇,后面兩篇分別是插入和刪除。

            上一章總結過BST(http://www.wutianqi.com/?p=2430),BST在高度較小時,可以獲得很好的性能(因為BST的操作的平均時間為O(lgn)),但是在高度較大時,則性能就一般。而紅黑樹“近似平衡”,于是降低了平均時間,再者,紅黑樹并不追求“完全平衡”——它只要求部分地達到平衡要求,降低了對旋轉的要求,從而提高了性能。

            談到紅黑樹的用途,最廣為人知的應該就是紅黑樹在C++ STL中的應用了,在set, multiset, map, multimap等中,都應用了紅黑樹(具體大家可以去網上搜搜)。

             

            下面給出紅黑樹和黑高度的定義:

            滿足下面幾個條件(紅黑性質)的二叉搜索樹,稱為紅黑樹
            1. 每個結點或是紅色,或是是黑色。
            2. 根結點是黑的。
            3. 所有的葉結點(NULL)是黑色的。(NULL被視為一個哨兵結點,所有應該指向NULL的指針,都看成指向了NULL結點。)
            4. 如果一個結點是紅色的,則它的兩個兒子節點都是黑色的。
            5. 對每個結點,從該結點到其子孫結點的所有路徑上包含相同數目的黑結點。

            黑高度的定義:
            從某個結點出發(不包括該結點)到達一個葉結點的任意一條路徑上,黑色結點的個數成為該結點x的黑高度。

            下面就是一個紅黑樹:

            rbt1

            紅黑樹是二叉搜索樹的一種。它與普通二叉搜索樹不同的是,紅黑樹的每個節點都附加了另一個屬性――顏色,可以是紅色,也可以是黑色。通過對于每條路徑上節點顏色的規則進行限定,紅黑樹可以保證任何兩條從根部到樹葉的路徑節點個數相差不超過2倍。所以,紅黑樹是一種近似平衡的二叉搜索樹。

            紅黑樹的查找、最大值、最小值、前趨、后繼等操作,與普通的二叉搜索樹沒有什么區別。插入和刪除操作需要重新實現。僅僅用普通的二叉搜索樹的插入和刪除動作,可能會破壞紅黑樹本身的一些性質,因此,需要進行額外的處理。這些額外的處理主要是改變樹節點的顏色,或是改變樹的結構。

            關于旋轉:

            我把13-2手動畫了一次并添加了一些注釋:

            xuanzhuan 

            旋轉其實比較簡單,就不多說了,以下是代碼:

            void LeftRotate(RBTree &T, Node *x)
            {
                Node 
            *= x->rchild;
                x
            ->rchild = y->lchild;
                
            if(y->lchild != NULL)
                    y
            ->lchild->parent = x;
                y
            ->parent = x->parent;
                
            if(x->parent == NULL)
                    T 
            = y;
                
            else
                {
                    
            if(x == x->parent->lchild)
                        x
            ->parent->lchild = y;
                    
            else
                        x
            ->parent->rchild = y;
                }
                y
            ->lchild = x;
                x
            ->parent = y;
            }
             
            void RightRotate(RBTree &T, Node *x)
            {
                Node 
            *= x->rchild;
                x
            ->rchild = y->lchild;
                
            if(y->lchild != NULL)
                    y
            ->lchild->parent = x;
                y
            ->parent = x->parent;
                
            if(x->parent == NULL)
                    T 
            = y;
                
            else
                {
                    
            if(x == x->parent->lchild)
                        x
            ->parent->lchild = y;
                    
            else
                        x
            ->parent->rchild = y;
                }
                y
            ->lchild = x;
                x
            ->parent = y;
            }

             

            下一篇是關于插入。

             

            在我獨立博客上的原文:http://www.wutianqi.com/?p=2438

            歡迎大家互相學習,互相討論!

            posted @ 2011-05-07 09:13 Tanky Woo 閱讀(1679) | 評論 (3)編輯 收藏
                 摘要: 建議先看看前言:http://www.shnenglu.com/tanky-woo/archive/2011/04/09/143794.html 推薦在看算法導論的這一章之前先看看嚴蔚敏老師在《數據結構》上的二叉查找樹。 整體來說二叉查找樹不難,就是插入和刪除節點時讓人糾結,我就是在刪除節點時各種糾結了。 二叉樹執行基本操作的時間與樹的高度成正比。 首先說下二叉查找樹的性質: 設x為二叉查...  閱讀全文
            posted @ 2011-05-03 12:43 Tanky Woo 閱讀(1872) | 評論 (0)編輯 收藏

            建議先看看前言:http://www.shnenglu.com/tanky-woo/archive/2011/04/09/143794.html

             

            第10章沒法說,數據結構還是看嚴奶奶的比較好,所以《算法導論》上的這一章我隨便瞄了幾眼就過去了,不過話說回來,數據結構非常重要!!!所以,大家最好把嚴蔚敏的《數據結構》認認真真的看N遍!!!

            另外,推薦看看這個:

            數據結構的源碼實現:http://www.cppleyuan.com/viewthread.php?tid=418

             

            第11章散列表也屬于數據結構方面的知識,第10章只是講了最基本的幾個結構。這一章也很簡單,其實就是介紹了一些概念及思想,很容易理解。(你可以把散列表想象成平時用的英語字典,26個英文字母就是下標,通過它來定位你要查的單詞。)

            所以這一章我就不重復去打出概念了,我把幾個散列函數和處理碰撞的方法放在圖表里方便對比。

             

            ①.散列表的優點:出色的期望性能。

            ②.引出:

            直接尋址表(P132)的缺點:

            1.全域U也許會很大。

            2.實際關鍵字域K也許相對于U會很小。

            由此引出了散列表。

            以下是我總結對比的表:

            sanlie1

            sanlie4

             

            這一章我也不知道該怎么說,表面上感覺比較簡單,但是如果深入研究,會發現它的內容太多了,而且很好很強大。所以還是建議大家看看書也許以后深入了解了我會再補充。

            這幾天主要在研究紅黑樹在,那個暈啊,不過總算弄明白了,心情也跟著很爽,接下來的一些章節都比較麻煩了,大家一起加油!


            在我獨立博客上的原文:http://www.wutianqi.com/?p=2419

            歡迎大家互相學習,互相討論!

            posted @ 2011-04-29 14:14 Tanky Woo 閱讀(1163) | 評論 (0)編輯 收藏

            建議先看看前言:http://www.shnenglu.com/tanky-woo/archive/2011/04/09/143794.html

            這一章的內容很簡單,基本都是一些概念。

            第i個順序統計量:在一個由n個元素組成的集合中,第i個順序統計量(order statistic)是該集合中第i小的元素。

            最小值是第1個順序統計量(i=1)

            最大值是第n個順序統計量(i=n)

            中位數:一個中位數(median)是它所在集合的“中點元素”,當n為奇數時,i=(n+1)/2,當n為偶數是,中位數總是出現在1 (下中位數)和2 (上中位數)。

            找最大值/最小值問題,通過比較n-1次可以得出結果。

            MINIMUM(A)
            1  minA[1]
            2  for i ← 2 to length[A]
            3         do if min > A[i]
            4                then minA[i]
            5  return min

            如果要同時找出最大值和最小值,則比較次數最少并不是2*n-2,而是3 ,我們可以將一對元素比較,然后把較大者于max比較,較小者與min比較,這樣就只需要3

            如果是一般的選擇問題,即找出一段序列第i小的數,看起來要比找最大值或最小值要麻煩,其實兩種問題的漸進時間都是4

            首先看看這個強悍的偽代碼:

            RANDOMIZED-SELECT(A, p, r, i)
            1  if p = r
            2      then return A[p]
            3  q ← RANDOMIZED-PARTITION(A, p, r)
            4  kq - p + 1
            5  if i = k          ? the pivot value is the answer
            6      then return A[q]
            7  elseif i < k
            8      then return RANDOMIZED-SELECT(A, p, q - 1, i)
            9  else return RANDOMIZED-SELECT(A, q + 1, r, i - k)

            這個算法利用了隨機化的Partition算法,這個實在第七章的隨機化快排中講到:http://www.wutianqi.com/?p=2368,不記得的可以先復習下前面的快排。

            這個隨機化的選擇算法返回數組A[p..r]中第i小的元素。

            具體實現如下:

             1 /*
             2 Author: Tanky Woo
             3 Blog:   www.WuTianQi.com
             4 About:  《算法導論》第9章 查找序列第i小的數字
             5 */
             6  
             7 #include <iostream>
             8 #include <cstdlib>
             9 using namespace std;
            10  
            11 int Partition(int *arr, int beg, int end)
            12 {
            13     int sentinel = arr[end];
            14     int i = beg-1;
            15     for(int j=beg; j<=end-1++j)
            16     {
            17         if(arr[j] <= sentinel)
            18         {
            19             i++;
            20             swap(arr[i], arr[j]);
            21         }
            22     }
            23     swap(arr[i+1], arr[end]);
            24  
            25     return i+1;
            26 }
            27  
            28 int RandomPartition(int *arr, int beg, int end)
            29 {
            30     int i = beg + rand() % (end-beg+1);
            31     swap(arr[i], arr[end]);
            32     return Partition(arr, beg, end);
            33 }
            34  
            35  
            36 int RandomSelect(int *a, int p, int r, int i)
            37 {
            38     if(p == r)
            39         return a[p];
            40     int q = Partition(a, p, r);
            41     int k = q-p+1;
            42     if(i == k)
            43         return a[q];
            44     else if(i < k)
            45         return RandomSelect(a, p, q-1, i);
            46     else
            47         return RandomSelect(a, q+1, r, i-k);
            48 }
            49  
            50 int main()  
            51 {  
            52     int a[] = {08910021528332763};  
            53     int num = 9;   
            54     int ith;
            55     cout << "序列為: ";
            56     for(int i=1; i<=num; ++i)  
            57         cout << a[i] << " ";
            58     cout << endl;
            59     ith = RandomSelect(a, 1, num, 2);
            60     cout << "序列中第2小的數字是: " << ith << endl;
            61     getchar();
            62  
            63     return 0;  
            64 }

            結果如圖:
            5

            在(89, 100, 21, 5, 2, 8, 33, 27, 63)中查找第二小的數字是5. 

            該算法的平均情況性能較好,并且又是隨機化的,所有沒有哪一種特別的輸入會導致最壞情況發生。



            在我獨立博客上的原文:http://www.wutianqi.com/?p=2395
            歡迎大家互相學習,互相探討。
            posted @ 2011-04-26 13:00 Tanky Woo 閱讀(1571) | 評論 (1)編輯 收藏
                 摘要: 建議先看看前言 : http://www.shnenglu.com/tanky-woo/archive/2011/04/09/143794.html 這一節講的是非線性排序。 一.計數排序(Counting Sort) 基本思想:對每一個輸入元素x,確定出小于x的元素個數。 適用范圍:適用于輸入是由小范圍的整數構成的序列。 穩定性:算法是穩定的。 具體實現:  1 ...  閱讀全文
            posted @ 2011-04-24 09:28 Tanky Woo 閱讀(1517) | 評論 (4)編輯 收藏

            建議先看看前言 : http://www.shnenglu.com/tanky-woo/archive/2011/04/09/143794.html

             

            第八章將介紹幾種非比較排序—計數排序,基數排序,桶排序,這三種排序都在線性時間下運行的。

            這一節決策樹其實是對前面的堆排序,快排等是最優的比較算法的證明,

            首先說下《算法導論》上對決策樹的定義:一棵決策樹是一棵滿二叉樹(注意看下面解釋),表示某排序算法作用于給定輸入所做的所有比較,而控制結構,移動等都被忽略了。

            注意:這里個人認為定義是錯誤的,決策樹不是一棵滿二叉樹,連完全二叉樹都不是。(不知道有沒有朋友看到這里和我想法一樣?)

            首先看看只有三個元素時,決策樹的圖:

            jueceshu

            在決策樹中,每個內結點都用i:j表示比較下標為i數組元素與下標為j的數組元素的大小。每一個葉結點是一個n個元素的全排列。

            所以排序算法的執行對應于遍歷一條從樹的根到葉結點的路徑

            因為有n個結點,根據高中學的組合排列知識,知道有n!個情況,也就是n!個葉子結點。

            在決策樹中,從根到任意一個可達葉結點之間的最長路徑的長度,表示對應的排序算法中最壞情況下的比較次數。這樣,一個比較算法的最壞情況的比較次數就是其決策樹的高度

            定理8.1證明了任意一個比較算法在最壞情況下都需要做?(n lg n)次的比較。這個證明比較簡單,可以看看書上的證明過程。

            這一節其實沒什么內容,就是一點基本的概念,以及了解比較算法可以通過轉換為決策樹這個模型去理解。

             

            在我獨立博客上的原文:http://www.wutianqi.com/?p=2372
            歡迎大家互相學習,互相探討。
            posted @ 2011-04-21 13:42 Tanky Woo 閱讀(1535) | 評論 (0)編輯 收藏
            推薦先看看前言:http://www.shnenglu.com/tanky-woo/archive/2011/04/09/143794.html

            其實這一篇我老早就寫過了,只不過最近在總結《算法導論》,而第七章就是快速排序,我當初總結的快排也是根據算法導論來的,為了方便大家閱讀,我在這里把曾經寫過的重新再貼一遍。


            前幾天寫過一個堆排序的文章(http://www.wutianqi.com/?p=1820),里面謝了很多講解和代碼注釋,個人感覺快速排序不是很難,所以不想寫講解,也不需要寫注釋,大家如果不明白什么是快速排序,可以去看下文章最后我推薦的幾個鏈接。

             

            我查過網上很多關于快排的文章和代碼,但是基本都是最原始的快排,即霍爾(Hoare)快排。想必大家也沒有注意這些,我準備把霍爾快排,算法導論上的快排和隨機化快排的代碼一起發出來,供大家對比與學習,歡迎大家和我探討

            代碼一.霍爾快排:

            /*
             * Author: Tanky Woo
             * Blog:   www.WuTianQi.com
             * Note:   快速排序版本1 --- Hoare-Partition
             
            */
             
            #include 
            <iostream>
            using namespace std;
             
            int num;
             
            void swap(int &a, int &b)
            {
                
            int temp = a;
                a 
            = b;
                b 
            = temp;
            }
             
            void PrintArray(int *arr)
            {
                
            for(int i=1; i<=num; ++i)
                    cout 
            << arr[i] << " ";
                cout 
            << endl;
            }
             
            int Partition1(int *arr, int beg, int end)
            {
                
            int low = beg, high = end;
                
            int sentinel = arr[beg];
                
            while(low < high)
                {
                    
            while(low<high && arr[high]>=sentinel)
                        
            --high;
                    arr[low] 
            = arr[high];
                    
            while(low<high && arr[low]<=sentinel)
                        
            ++low;
                    arr[high] 
            = arr[low];
                }
                arr[low] 
            = sentinel;
             
                cout 
            << "排序過程:";
                PrintArray(arr);
                
            return low;
            }
             
            void QuickSort(int *arr, int beg, int end)
            {
                
            if(beg < end)
                {
                    
            int pivot = Partition1(arr, beg, end);
                    QuickSort(arr, beg, pivot
            -1);
                    QuickSort(arr, pivot
            +1, end);
                }
            }
             
            int main()
            {
                
            int arr[100];
                cout 
            << "Input the num of the elements:\n";
                cin 
            >> num;
                cout 
            << "Input the elements:\n";
                
            for(int i=1; i<=num; ++i)
                    cin 
            >> arr[i];
                QuickSort(arr, 
            1, num);
                cout 
            << "最后結果:";
                PrintArray(arr);
                
            return 0;
            }

            代碼二.《算法導論》里講的快排:

            /*
             * Author: Tanky Woo
             * Blog:   www.WuTianQi.com
             * Note:   快速排序版本2---《算法導論》
             
            */
             
            #include 
            <iostream>
            using namespace std;
             
            int num;
             
            void swap(int &a, int &b)
            {
                
            int temp = a;
                a 
            = b;
                b 
            = temp;
            }
             
            void PrintArray(int *arr)
            {
                
            for(int i=1; i<=num; ++i)
                    cout 
            << arr[i] << " ";
                cout 
            << endl;
            }
             
            int Partition2(int *arr, int beg, int end)
            {
                
            int sentinel = arr[end];
                
            int i = beg-1;
                
            for(int j=beg; j<=end-1++j)
                {
                    
            if(arr[j] <= sentinel)
                    {
                        i
            ++;
                        swap(arr[i], arr[j]);
                    }
                }
                swap(arr[i
            +1], arr[end]);
             
                cout 
            << "排序過程:";
                PrintArray(arr);
                
            return i+1;
            }
             
            void QuickSort(int *arr, int beg, int end)
            {
                
            if(beg < end)
                {
                    
            int pivot = Partition2(arr, beg, end);
                    QuickSort(arr, beg, pivot
            -1);
                    QuickSort(arr, pivot
            +1, end);
                }
            }
             
            int main()
            {
                
            int arr[100];
                cout 
            << "Input the num of the elements:\n";
                cin 
            >> num;
                cout 
            << "Input the elements:\n";
                
            for(int i=1; i<=num; ++i)
                    cin 
            >> arr[i];
                QuickSort(arr, 
            1, num);
                cout 
            << "最后結果:";
                PrintArray(arr);
                
            return 0;
            }

            代碼三.隨機快排:

            /*
             * Author: Tanky Woo
             * Blog:   www.WuTianQi.com
             * Note:   快速排序版本3 --- 隨機化版本
             * 解決待排序元素相差很大的情況
             
            */
             
             
            #include 
            <iostream>
            #include 
            <cstdlib>
            using namespace std;
             
            int num;
             
            void swap(int &a, int &b)
            {
                
            int temp = a;
                a 
            = b;
                b 
            = temp;
            }
             
            void PrintArray(int *arr)
            {
                
            for(int i=1; i<=num; ++i)
                    cout 
            << arr[i] << " ";
                cout 
            << endl;
            }
             
            int Partition3(int *arr, int beg, int end)
            {
                
            int sentinel = arr[end];
                
            int i = beg-1;
                
            for(int j=beg; j<=end-1++j)
                {
                    
            if(arr[j] <= sentinel)
                    {
                        i
            ++;
                        swap(arr[i], arr[j]);
                    }
                }
                swap(arr[i
            +1], arr[end]);
             
                cout 
            << "排序過程:";
                PrintArray(arr);
                
            return i+1;
            }
             
            int RandomPartition(int *arr, int beg, int end)
            {
                
            int i = beg + rand() % (end-beg+1);
                swap(arr[i], arr[end]);
                
            return Partition3(arr, beg, end);
            }
             
             
            void RandomQuickSort(int *arr, int beg, int end)
            {
                
            if(beg < end)
                {
                    
            int pivot = RandomPartition(arr, beg, end);
                    RandomQuickSort(arr, beg, pivot
            -1);
                    RandomQuickSort(arr, pivot
            +1, end);
                }
            }
             
            int main()
            {
                
            int arr[100];
                cout 
            << "Input the num of the elements:\n";
                cin 
            >> num;
                cout 
            << "Input the elements:\n";
                
            for(int i=1; i<=num; ++i)
                    cin 
            >> arr[i];
                RandomQuickSort(arr, 
            1, num);
                cout 
            << "最后結果:";
                PrintArray(arr);
                
            return 0;
            }

            最后,我想說下,隨機化的快排一般適用于待排序的數據之間相差較大的情況下。

            這里給出幾篇網上講得不錯的文章:

            1.http://bbs.chinaunix.net/viewthread.php?tid=1011316

            算是一個討論帖。很給力!

            2.http://www.javaeye.com/topic/561718

            講得比較詳細,不過代碼是Java的。

            3.http://tayoto.blog.hexun.com/25048556_d.html

            4.http://www.360doc.com/content/10/1106/11/1317564_67067368.shtml

            概念上很詳細。

            5.http://blog.csdn.net/wssxy/archive/2008/12/05/3448642.aspx

            一篇講快排的佳作!

            6.http://www.cnblogs.com/chinazhangjie/archive/2010/12/09/1901491.html

            小杰的文章,用C++模板類寫的。大家可以去學習學習。


            在我獨立博客上的原文:http://www.wutianqi.com/?p=2368
            歡迎大家互相學習,互相探討。
            posted @ 2011-04-19 18:08 Tanky Woo 閱讀(2026) | 評論 (7)編輯 收藏

            建議先看看前言:http://www.shnenglu.com/tanky-woo/archive/2011/04/09/143794.html

            上一章總結是的堆排序算法,這一章同樣是利用了堆這種數據結構,實現在是優先級隊列

            根據堆分為最大堆,最小堆,所以優先級隊列也可以分為最大優先級隊列最小優先級隊列

            優先級隊列的概念和用途書上已經寫的很清楚了,我就不再打一遍了。直接寫出具體實現。

            在實現前先說幾點:

            1.上一章說過,堆的length和heapsize要區分清楚,這一章的優先級隊列里就用到了。

            2.優先級隊列用到了上一章的一些函數比如MaxHeapify(),不記得的可以復習下上一章。

            以下是代碼及講解(此處實現的是最大優先級隊列):

            // 堆應用之優先級隊列
            // Tanky Woo
            // Blog: www.WuTianQi.com
            #include <iostream>
            using namespace std;
            const int INF = 999999;
             
            /////////////////////////////////////////////////////////
            ////////////// 以下代碼在堆排序中已講解過 ///////////////
            void MaxHeapify(int *a, int i, int len)
            {
                
            int lt = 2*i, rt = 2*i+1;
                
            int largest;
                
            if(lt <= len && a[lt] > a[i])
                    largest 
            = lt;
                
            else
                    largest 
            = i;
                
            if(rt <= len && a[rt] > a[largest])
                    largest 
            = rt;
                
            if(largest != i)
                {
                    
            int temp = a[i];
                    a[i] 
            = a[largest];
                    a[largest] 
            = temp;
                    MaxHeapify(a, largest, len);
                }
            }
             
            void BuildMaxHeap(int *a, int size)
            {
                
            for(int i=size/2; i>=1--i)
                    MaxHeapify(a, i, size);
            }
             
            void PrintArray(int data[], int size)
            {
                
            for (int i=1; i<=size; ++i)
                    cout 
            <<data[i]<<"  ";
                cout
            << endl << endl;
            }
            ////////////////////////////////////////////////////////////
             
            // 返回具有最大關鍵字的元素
            int HeapMaximum(int *a)
            {
                
            return a[1];
            }
             
            // 去掉并返回具有最大關鍵字的元素
            // 注意:這里每次MaxHeapify的是heapsize
            int HeapExtractMax(int *a, int &heapsize)
            {
                
            if(heapsize < 1)
                    cout 
            << "Heap Underflow" << endl;
                
            int max = a[1];
                a[
            1= a[heapsize];
                
            --heapsize;
                MaxHeapify(a, 
            1, heapsize);
                
            return max;
            }
             
            // 將元素a[i]的值增加到key
            void HeapIncreaseKey(int *a, int i, int key)
            {
                
            if(key < a[i])
                    cout 
            << "New key is smaller than current key" << endl;
                a[i] 
            = key;
                
            while(i > 1 &&a[i/2< a[i])
                {
                    
            int temp = a[i];
                    a[i] 
            = a[i/2];
                    a[i
            /2= temp;
                    i 
            /= 2;
                }
            }
             
            // 插入關鍵字為key的元素
            void MaxHeapInsert(int *a, int key, int &heapsize)
            {
                
            ++heapsize;
                a[heapsize] 
            = -INF;
                HeapIncreaseKey(a, heapsize, key);
            }
             
             
             
            int main()
            {
                
            int len, heapsize;
                
            int arr[100= {0151395128740621};
                
            // 區別len 和 heapsize
                
            // heapsize是堆的大小,而len是初始數組的總大小。
                len = heapsize = 12;
             
                
            // 首先建堆
                BuildMaxHeap(arr, len);
                cout 
            << "建堆后: " << endl;
                PrintArray(arr, len);
             
                
            // 使用HeapMaximum
                cout << "當前最大的元素是: " << endl;
                cout 
            << HeapMaximum(arr) << endl << endl;
             
                
            // 使用HeapExtractMax
                cout << "使用HeapExtractMax后: " << endl;
                HeapExtractMax(arr,heapsize);
                PrintArray(arr, heapsize);
             
                
            // 再次使用HeapExtractMax
                cout << "再次使用HeapExtractMax后: " << endl;
                HeapExtractMax(arr,heapsize);
                PrintArray(arr, heapsize);
             
                
            // 使用HeapIncreaseKey
                cout << "使用HeapIncreaseKey后: " << endl;
                HeapIncreaseKey(arr, 
            215);
                PrintArray(arr, heapsize);
             
                
            // 使用MaxHeapInsert
                cout << "使用MaxHeapInsert后: " << endl;
                MaxHeapInsert(arr, 
            28, heapsize);
                PrintArray(arr, heapsize);
            }

            以下是運行結果:

            youxianji

            看上圖的結果:

            在第二次使用HeapExtractMax后,把第二個數字即6設為15,更新后,結果就是HeapIncreaseKey的輸出。

            Tanky Woo 標簽:

            個人Blog同步發表: http://www.wutianqi.com/?p=2349
            posted @ 2011-04-17 15:00 Tanky Woo 閱讀(1519) | 評論 (0)編輯 收藏

            建議先看看前言:http://www.shnenglu.com/tanky-woo/archive/2011/04/09/143794.html

            首先介紹幾個概念:

            衛星數據:一個帶排序的的數通常是有一個稱為記錄的數據集組成的,每一個記錄有一個關鍵字key,記錄的其他數據稱為衛星數據。

            原地排序:在排序輸入數組時,只有常數個元素被存放到數組以外的空間中去。

             

            在第二章介紹了兩種排序:插入排序和合并排序,接下來兩章要介紹的是推排序和快速排序,這四個排序都屬于比較排序(comparison sort)。

             

            我以前總結過堆排序,并具體實現了堆排序,代碼中給出了詳細的注釋,所以在這里就不重復發了,大家可以去看看,個人覺得總結的還是比較給力的:

            http://www.wutianqi.com/?p=1820

            這里再補充幾點:

            1.區別length[A]和heap-sort[A]。(P73)(這個在下一篇的優先級隊列中將會具體區別)

            2.總體上看堆排序由三個函數組成:①.MAX-HEAPIFY ②.BUILD-MAX-HEAP ③.HEAP-SORT

             

            另外,在這里給大家補充一點個人經驗,有時理論難以理解,代碼難以理解,這個時候,就要靠秘訣了:拿起手中的筆和紙,自己給出一組輸入,按照書上的代碼,自己去模擬這組輸入的執行過程。(這個過程人人都知道,但并不是人人都去做了!學算法,就要自己去模擬,去畫圖,去推!怎么樣容易理解就怎么去做!)

            所以這也是我喜歡《算法導論》的原因,接下來,就要強烈推薦大家看《算法導論》上非常非常給力的堆排序實現圖了—圖6-4。

             

             

            總結:本章最基礎也是最重要的就是理解堆這種結構!

            堆是什么?來看看《算法導論》上的圖6-1:

            dui

            圖(a)是一個最大堆,圖(b)是最大堆的數組表示。可以看到堆的數組并不是已排序好的。

            讓我們來回憶下最大堆的定義(P74):

            在最大堆中,最大堆特性是指除了根以外的每個結點i,有A[PARENT(i)] >= A[i]。這樣,堆的最大元素就存放在根結點中。

            對,堆排序就是利用的這個特性—“堆的最大元素就存放在根結點中”

            每次堆化,這樣就找到了當前堆的最大元素。

            所以說,理解了其本質特征,堆排序其實很簡單的。

            至于堆排序的具體應用,在后面的最短路算法—Dijkstra中,會用到由堆來優化普通的Dijkstra算法。

            下一篇將實現最大優先級隊列。

            Tanky Woo 標簽:
            posted @ 2011-04-15 12:43 Tanky Woo 閱讀(1314) | 評論 (0)編輯 收藏

            建議先看看前言:http://www.shnenglu.com/tanky-woo/archive/2011/04/10/143850.html#143880

            因為《算法導論》第一部分1~5章的理論性太強,研究過多容易糾結,所以索性合起來快點講過去。

            第四章:

            這一章講的是遞歸式(recurrence),遞歸式是一組等式或不等式,它所描述的函數是用在更小的輸入下該函數的值來定義的。

            本章講了三種方法來解遞歸式,分別是代換法,遞歸樹方法,主方法。

            1.代換法(Substitution method)(P38~P40)

            定義:即在歸納假設時,用所猜測的值去代替函數的解。

            用途:確定一個遞歸式的上界或下界。

            缺點:只能用于解的形式很容易猜的情形。

            總結:這種方法需要經驗的積累,可以通過轉換為先前見過的類似遞歸式來求解。

            2.遞歸樹方法(Recursion-tree method)

            起因:代換法有時很難得到一個正確的好的猜測值。

            用途:畫出一個遞歸樹是一種得到好猜測的直接方法。

            分析(重點):在遞歸樹中,每一個結點都代表遞歸函數調用集合中一個子問題的代價。將遞歸樹中每一層內的代價相加得到一個每層代價的集合,再將每層的代價相加得到遞歸式所有層次的總代價。

            總結:遞歸樹最適合用來產生好的猜測,然后用代換法加以驗證。

            遞歸樹擴展過程:①.第二章2.3.2節分析分治法時圖2-5(P21~P22)的構造遞歸樹過程;②.第四章P41圖4-1的遞歸樹構造過程;這兩個圖需要好好分析。

            3.主方法(Master method)

            優點:針對形如T(n) = aT(n/b) + f(n)的遞歸式

            缺點:并不能解所有形如上式的遞歸式的解。

            具體分析:

            T(n) = aT(n/b) + f(n)描述了將規模為n的問題劃分為a個子問題的算法的運行時間,每個子問題的規模為n/b。

            在這里可以看到,分治法就相當于a=2, b=2, f(n) = O(n).

            主方法依賴于主定理:(圖片點擊放大)

            zhudingli 圖片可以不清晰,可以看書。

            主定理的三種情況,經過分析,可以發現都是把f(n)與1 比較。

            第一種情況是1 更大,第二種情況是1 與f(n)相等,第三種情況是f(n)更大。

            但是,這三種情況并未完全覆蓋所有可能的f(n):

            第一種情況是f(n)多項式的小于1 ,而第三種情況是f(n)多項式的大于1 ,即兩者相差的是2 。如果兩者相差的不是2 ,則無法用主定理來確定界。

            比如算法導論P44最下面的3 就不能用主定理來判斷。

            至于主定理的證明,有興趣的可以拿筆在紙上推算,反正我這里是沒看的,畢竟時間有限,要選擇性的學習。

            第五章:

            本章是圍繞一個雇傭問題展開的。

            問題:有一批參與面試的人,你要一個個面試(面試每個人都要花費c1),如果當前面試者比自己的助理能力強,則辭掉當前助理的,并把當前面試者提拔為助理(雇傭一個人要花費c2),一直面試完所有人。

            這里考慮的是面試所花的money,假設總共有N人參加面試,有M人被雇傭過,則花費O(N*c1 + M*c2),因為參與面試的人員順序是不確定的,所以要花費的money也是不確定的(N*c1是確定的,而M是不確定的,所以M*c2也是不確定的)。

            首先介紹兩個概念:

            1.概率分析:指在問題的分析中應用概率的技術。

            2.隨機算法:如果一個算法的行為不只是由輸入決定,同時也由隨機數生成器所產生的數值決定,則成這個算法是隨機的。

            書上講的理論性有點強,我這里用自己的話來說下:

            首先說下概率分析,因為前面講到過:雇傭所需的花費與輸入序列有關,有N個面試人員(考慮每個人的能力不一樣),則一共有N!中排列情況(即每種排列出現的概率是1/(N!)),于是假設每種排列花費Ti元,則所有供花費:

            T1/(N!) + T2/(N!) + … + TN/(N!)。

            其實這里可以結合高中學的正態分布來理解,都是講的每種情況出現的概率,思想差不多,所以這里也不需要什么概率論的知識,都是一些常識。

            順便補充一下:5.2節的指示器隨機變量就是用的高中學的期望用期望來表示概率。

            再說下隨機算法,對于上面概率分析時的方法,雖然面試人員的排列是不確定的。但是如果當排列確定后,則所需花費也就確定了。而對于隨機算法,就算排列確定,其花費也是不確定的。即隨機發生在算法上,而不是發生在輸入分布上。這就是概率分析與隨機算法之間的區別

            比如按書上的,可以給每個人員隨機生成一個優先級,或者把每一個面試人員與其后的面試人員中隨機一員交換,來產生一個隨機的序列。

            我以前總結過一些隨機算法,有興趣的朋友可以去看看:

            1.《隨機化算法(1) — 隨機數》

            2.《隨機化算法(2) — 數值概率算法》

            3.《隨機化算法(3) — 舍伍德(Sherwood)算法》

            4.《隨機化算法(4) — 拉斯維加斯(Las Vegas)算法》

            5.《隨機化算法(5) — 蒙特卡羅(Monte Carlo)算法》

            另外,比如像C/C++中庫函數rand()就是一個產生隨機變量的函數,但是它并不是真正意義上的隨機函數,所以稱之為偽隨機函數。因為當srand(seed)設置的seed一樣時,則rand()產生的隨機數也一樣,所以通常可以通過rand(-1)來把當前時間作為種子模擬隨機函數。

            補充:在第五章的5.4節給出了幾個題目及其分析,這幾個題目都很有趣,不過對于數學也相對有一定的要求。其實可以很簡化的想:概率和期望是互相轉化的,這幾題就可以考慮是去求期望的。

            我昨天在論壇出了一個邏輯面試題:一樓到十樓的每層電梯門口都放著一顆鉆石,鉆石大小不一。你乘坐電梯 從一樓到十樓,每層樓電梯門都會打開一次,只能拿一次鉆石,問怎樣才能拿到最大的一顆?

            想必好多人都看過這題,網上的解答多種多項,我覺得此題應該考察的是最優解問題,按照最優解的思路,此題沒有100%的解決方法,只能盡量使其期望更高,也就是概率更大。這一題可以說是數學和哲學的完美結合,有點像人生,總想得到更多,但又怕后面的都不行,各種糾結啊。。。

            總的來說,第五章說來說去都是一個期望的問題。

            posted @ 2011-04-12 12:40 Tanky Woo 閱讀(2348) | 評論 (0)編輯 收藏
            僅列出標題
            共7頁: 1 2 3 4 5 6 7 
            亚洲成人精品久久| 久久午夜无码鲁丝片秋霞| 欧美一区二区三区久久综| 欧美大战日韩91综合一区婷婷久久青草 | 久久996热精品xxxx| 久久er热视频在这里精品| 亚洲综合精品香蕉久久网| 亚洲AV无码成人网站久久精品大| 久久免费看黄a级毛片| 亚洲AV成人无码久久精品老人| 亚洲精品乱码久久久久久蜜桃| 伊人久久大香线蕉综合5g| 久久精品中文字幕大胸| 亚洲午夜久久久影院伊人| 久久亚洲AV成人无码电影| 精品综合久久久久久888蜜芽| 国产亚洲综合久久系列| 精品国产福利久久久| 国产ww久久久久久久久久| 久久久青草青青国产亚洲免观| 中文字幕无码av激情不卡久久 | 日本高清无卡码一区二区久久| 久久久久国产亚洲AV麻豆| 99久久香蕉国产线看观香| 久久久久久人妻无码| 国产69精品久久久久9999| 久久久久亚洲国产| 国产精品一久久香蕉产线看| 久久国产免费| 久久精品水蜜桃av综合天堂| 精品国产91久久久久久久a| 三级韩国一区久久二区综合| 天天躁日日躁狠狠久久| 久久久久久久亚洲精品 | 欧洲精品久久久av无码电影| 青青草原1769久久免费播放| 伊人久久无码精品中文字幕| 伊人久久大香线蕉精品| 免费久久人人爽人人爽av| 99久久精品免费看国产免费| 久久香综合精品久久伊人|