數據結構_郝斌老師自學大綱

數據結構概述(教材選用嚴蔚敏、吳偉民,該書程序是僞算法
                具體的程序是高一凡,西電的,大牛,只有
                程序。還有一本書,臺灣的黃國瑜自己寫的
                只有思路,程序是另外一個合作的清華的寫
                的,可惜很多錯的。)
學完數據結構之後會對面向過程的函數有一個更深的瞭解

   定義
       我們如何把現實中大量而複雜的問題以特定的數據類型(單
       個數據怎樣存儲?)和特定的存儲結構(個體的關係) 
       保存到主存儲器(內存)中,以及在此基礎上爲實現某個功能
       (比如查找某個元素,刪除某個元素,對所有元素進行排序)
       而執行的相應操作,這個相應的操作也叫算法。(比如班裏有
       15個人,其信息量也許一個數組就搞定了,但是假如10000個,
       怎麼辦?內存也許沒有這麼多連續的空間,所以我們改用鏈表,
       you see這就是與存儲有關係。又比如,人事管理系統的信息存儲,
       因爲存在着上下級的關係,所以數組和鏈表就無能爲力了,
       這時候我們用樹,再比如我們做的是交通圖,站和站之間肯定要連通,這
       時候以上的存儲方式又無能爲力了,所以我們又有了圖。圖
       就是每個結點都可以和其他結點產生聯繫。所以當我們要解決
       問題時,首先要解決的是如何把這些問題轉換成數據,先保存
       到我們的主存中,)

       數據結構 = 個體 + 個體的關係
       算法 = 對存儲數據的操作
   算法
        解題的方法和步驟

        衡量算法的標準
            1、時間複雜度
                大概程序要執行的次數,而非執行的時間。

            2、空間複雜度
                算法執行過程中大概所佔用的最大內存

            3、難易程度(主要是應用方面看重)

            4、健壯性(不能別人給一個非法的輸入就掛掉)

    數據結構的地位
        數據結構是軟件中最核心的課程

        程序 = 數據的存儲+數據的操作+可以被計算機執行的語言(已經提供)

(學完數據結構,想用一種語言去實現它,必須有指針,數據結構java
版,就胡扯,變味,因爲我們要講鏈表,就是通過指針鏈在一起的。比如
在java中A aa = new A();本質上,aa是個地址)   
預備知識
    指針
        指針的重要性:(內存是可以被CPU直接訪問的,硬盤不行
                        主要靠地址總線,數據總線,控制總線。)
            指針是C語言的靈魂
        定義
            地址
                地址就是內存單元的編號
                從0開始的非負整數
                範圍:0--FFFFFFFF[0-4G-1](地址線是32位,剛好控制2的32次)
            指針:
                指針就是地址  地址就是指針
                指針變量是存放內存單元地址的變量
                指針的本質是一個操作受限的非負整數(不能加乘除,只能減)
        分類:
            1、基本類型的指針

            2、指針和數組的關係

    結構體(C++中用類也能實現)
        爲什麼會出現結構體
            爲了表示一些複雜的數據,而普通的基本類型變量無法滿足要求

        什麼叫結構體
            結構體是用戶根據實際需要自己定義的複合數據類型

        如何使用結構體
            兩種方式:
                struct Student st = {1000, "zhangsan", 20}
                struct Student * pst = &st;

                1.
                    st.sid
                2.
                    pst->sid
                    pst所指向的結構體變量中的sid這個成員

        注意事項:
            結構體變量不能加減乘除,但可以相互賦值
            普通結構體變量和結構體指針變量作爲函數參數的傳遞

 (病毒就是靠訪問正在運行的那些程序所佔用的內存。Java中規定局部
 變量必須初始化,因爲這些變量一開始都是垃圾值,但是屬性不是必須
 初始化的,因爲已經默認初始化爲0)   
    動態內存分配和釋放(動態分配的內存一定要手動釋放,否則造成內存
                        泄露。)
(java中A aa = new A();其實就是 A *p = (A *)malloc(sizeof(A)))

模塊一:線性結構【把所有的結點用一根直線穿起來】
    連續存儲【數組】
        1、什麼叫做數組
            元素類型相同,大小相等(數組傳參,只要傳進去首地址和長度就行)
        2、數組的優缺點:
            優點:
                存取速度快
            缺點:
                事先必須知道數組的長度
                插入刪除元素很慢
                空間通常是有限制的
                需要大塊連續的內存塊
                插入刪除元素的效率很低



    離散存儲【鏈表】(我們搞底層的開發,類似於SUN公司的類)
        定義:
            n個節點離散分配
            彼此通過指針相連
            每個節點只有一個前驅節點,每個節點只有一個後續節點
            首節點沒有前驅節點,尾節點沒有後續節點。

            專業術語:
                    首節點:
                            第一個有效節點
                    尾節點:
                            最後一個有效節點
                    頭節點:
                            頭結點的數據類型和首節點的類型一樣
                            沒有存放有效數據,最最前面的,是在
                            首節點之前的,主要是爲了方便對鏈表
                            的操作。
                    頭指針:(指向頭)
                            指向頭節點的指針變量
                    尾指針:
                            指向尾節點的指針

(頭結點有可能很大,佔的內存可能大,假設我想造一個函數
輸出所有鏈表的值,那你如果不用頭指針類型做形參,那由於
不同鏈表的頭節點不一樣大小,這樣就沒辦法找出形參)


        確定一個鏈表需要幾個參數:(或者說如果期望一個函數對鏈表進行操作
                                    我們至少需要接收鏈表的那些信息???)
            只需要一個參數:頭指針,因爲通過它我們可以推出
            鏈表的所有信息。
(鏈表的程序最好一定要自己敲出來)
        分類:
            單鏈表
            雙鏈表:
                    每一個節點有兩個指針域

            循環鏈表
                    能通過任何一個節點找到其他所有的節點
            非循環鏈表

(java中變成垃圾內存則會自動釋放,但是C和C++則不會,所以要
手動釋放,否則會引起內存泄露。delete等於free)        
        算法:
            遍歷
            查找
            清空
            銷燬
            求長度
            排序
            刪除節點
            插入節點
算法:狹義的算法是與數據的存儲方式密切相關
      廣義的算法是與數據的存儲方式無關
      泛型:(給你一種假象,只不過牛人從內部都弄好了)
           利用某種技術達到的效果就是:不同的存儲方式,執行的操作是一樣的

算法的真正學法:很多算法你根本解決不了!!!!!!因爲很多都屬於
                數學上的東西,所以我們把答案找出來,如果能看懂就
                行,但是大部分人又看不懂,分三步,按照流程,語句,
                試數。這個過程肯定會不斷地出錯,所以不斷出錯,不斷
                改錯,這樣反覆敲很多次,纔能有個提高。實在看不懂
                就先背會。                   

        鏈表的優缺點:
                優點:
                    空間沒有限制
                    插入刪除元素很快
                缺點:
                    存取速度很慢。

    線性結構的兩種常見應用之一   棧   (存儲數據的結構)
        定義
            一種可以實現“先進後出” 的存儲結構
            棧類似於箱子

        分類
            靜態棧 (類似於用數組實現)
            動態棧 (類似於用鏈表實現)

        算法(往裏放,從裏取)
            出棧
            壓棧(參看Java中線程的例子,成產消費的例子)

        應用
            函數調用
            中斷
            表達式求值(用兩個棧,一個存放數字,一個存放符號)
            內存分配
            緩衝處理
            迷宮

    線性結構的兩種常見應用之二   隊列
        定義:
            一種可是實現“先進先出”的存儲結構
        分類:
            鏈式隊列:用鏈表實現

            靜態隊列:用數組實現
                靜態對流通常都必須是循環隊列,爲了減少
                內存浪費。

                循環隊列的講解:
                    1、 靜態隊列爲什麼必須是循環隊列
                    2、  循環隊列需要幾個參數來確定 及其含義
                        需要2個參數來確定
                            front

                            rear


                    3、 循環隊列各個參數的含義

                            2個參數不同場合不同的含義?    
                            建議初學者先記住,然後慢慢體會

                             1)隊列初始化
                                front和rear的值都是零
                             2)隊列非空
                                front代表隊列的第一個元素
                                rear代表了最後一個有效元素的下一個元素
                             3)隊列空
                                front和rear的值相等,但是不一定是零
                  4、    循環隊列入隊僞算法講解
                        兩步完成:
                        1)將值存入r所代表的位置
                        2)將r後移,正確寫法是 rear = (rear+1)%數組長度
                        錯誤寫法:rear=rear+1;

                    5、 循環隊列出隊僞算法講解
                        front = (front+1) % 數組長度

                    6、 如何判斷循環隊列是否爲空
                        如果front與rear的值相等,
                        則隊列一定爲空

                    7、 如何判斷循環隊列是否已滿
                        預備知識:
                            front的值和rear的值沒有規律,
                            即可以大,小,等。

                        兩種方式:
                            1、多增加一個表標識的參數
                            2、少用一個隊列中的元素(才一個,不影響的)
                            通常使用第二種方法
                            如果r和f的值緊挨着,則隊列已滿
                            用C語言僞算法表示就是:
                                if( (r+1)%數組長度 == f )
                                    已滿
                                else
                                    不滿

        隊列算法:
                            入隊
                            出隊
                    隊列的具體應用:
                            所有和事件有關的操作都有隊列的影子。
                            (例如操作系統認爲先進來的先處理)

    專題:遞歸【這對你的編碼能力是個質的飛躍,如果你想成爲一個很厲害的
    程序員,數據結構是必須要掌握的,因爲計算機專業的本科生也達不到這水
    平!計算機特別適合用遞歸的思想來解決問題,但是我們人類用遞歸的思想
    來考慮問題就會感到十分困擾,這也是很多學過遞歸的人一直都搞不明白的
    地方!那是不是遞歸可以隨便寫,當然不是,有些同學一用遞歸程序就死翹
    翹了。遞歸的思想是軟件思想的基本思想之一,在樹和圖論上面,幾乎全是
    用遞歸來實現的,最簡單,像求階乘這種沒有明確執行次數的問題,都是用
    遞歸來解決】
        定義:
            一個函數自己直接或間接調用自己(一個函數調用另外
            一個函數和他調用自己是一模一樣的,都是那三步,
            只不過在人看來有點詭異。)

        遞歸滿足的三個條件:
            1、遞歸必須得有一個明確的終止條件
            2、該函數處理的數據規模必須在遞減
            3、這個轉化必須是可解的。

        循環和遞歸:
                理論上循環能解決的,肯定可以轉化爲遞歸,但是這個
                過程是複雜的數學轉化過程,遞歸能解決不一定能轉化
                爲循環,我們初學者只要把經典的遞歸算法看懂就行,
                至於有沒有能力運用看個人。       

                遞歸:
                    易於理解
                    速度慢
                    存儲空間大
                循環
                    不易於理解
                    速度快
                    存儲空間小

        舉例:    
            1.求階乘
            2.1+2+3+4+。。。+100的和
            3.漢諾塔
            【漢諾塔】這不是線性遞歸,這是非線性遞歸!
            n=1      1
            n=2      3
            n=3      7
            .........
            .........
            n=64     264次方減1【這是個天文數字,就算世界上最快的計算機
            也解決不了,漢諾塔的負責度是2的n次方減1】問題很複雜,但真正解決
            問題的編碼只有三句。
            4.走迷宮(CS的實現)

            遞歸的運用:
                樹和森林就是以遞歸的方式定義的
                樹和圖的很多算法都是以遞歸來實現的
                很多數學公式就是以遞歸的方式定義的
                    斐波拉契序列
                        1 2 3 5 8 13 21 34。。。

爲何數據結構難學:因爲計算機內存是線性一維的,而我們要處理的數據
都是比較複雜的,那麼怎麼把這麼多複雜的數據保存在計算機中來保存本
身就是一個難題,而計算機在保存線性結構的時候比較好理解,尤其是數
組和鏈表只不過是連續和離散的問題,線性結構是我們學習的重點,因爲
線性算法比較成熟,無論C++還是Java中都有相關的工具例如Arraylist.
Linkedlist,但是在Java中沒有樹和圖,因爲非線性結構太複雜了,他的
操作遠遠大於線性結構的操作。即使SUN公司也沒造出來。                 
小複習一下:^_^
                邏輯結構:(就是在你大腦裏面能產生的,不考慮在計算機中存儲)
                            線性(用一根直線穿)
                                在計算機中存儲用:
                                數組
                                鏈表
                棧和隊列是一種特殊的線性結構,是具體應用。
                (操作受限的線性結構,不受限的應該是在任何地方可以增刪改查
                可以用數組和鏈表實現。只要把鏈表學會,棧和隊列都能搞定,數
                組稍微複雜一些。)               
                            非線性:
                                樹
                                圖
                物理結構:   
                                數組
                                鏈表          


模塊二:非線性結構(現在人類還沒有造出一個容器,能把樹和圖
                    都裝進去的,因爲他們確實是太複雜了)
(都要靠鏈表去實現)
    樹
            樹定義
                    專業定義:
                      1、有且只有一個稱爲根的節點
                      2、有若干個互不相交的子樹,這些子樹本身也是一棵樹

                    通俗定義:
                        1、樹是由節點和邊組成
                        2、每個節點只有一個父節點但可以有多個子節點
                        3、但有一個節點例外,該節點沒有根節點,此節點稱爲根節點

                    專業術語
                        節點    父節點      子節點
                        子孫    堂兄弟      
                        深度:
                            從根節點到最底層節點的層數稱之爲深度
                            根節點是第一層
                        葉子節點;(葉子就不能劈叉了)
                            沒有子節點的節點
                        非終端節點:
                            實際就是非葉子節點。
                        根節點既可以是葉子也可以是非葉子節點
                        度:
                            子節點的個數稱爲度。(一棵樹看最大的)         
            樹分類:
                一般樹
                    任意一個節點的子節點的個數都不受限制
                二叉樹(有序樹)
                    任意一個節點的子節點的個數最多兩個,且子節點
                    的位置不可更改。

                    分類:
                        一般二叉樹
                        滿二叉樹
                            在不增加樹的層數的前提下。無法再多
                            添加一個節點的二叉樹就是滿二叉樹。
                        完全二叉樹
                            如果只是刪除了滿二叉樹最底層最右邊的
                            連續若干個節點,這樣形成的二叉樹就是
                            完全二叉樹。

                森林
                    n個互不相交的樹的集合


一般的二叉樹要以數組的方式存儲,要先轉化成完全二叉樹,因爲如果你
只存有效節點(無論先序,中序,後序),則無法知道這個樹的組成方式
是什麼樣子的。


            樹的存儲(都是轉化成二叉樹來存儲)
                二叉樹的存儲
                    連續存儲【完全二叉樹】
                        優點:
                            查找某個節點的父節點和子節點(也包括判斷有咩有)速度很快
                        缺點:
                            耗用內存空間過大

                    鏈式存儲

                一般樹的存儲
                    雙親表示法
                        求父節點方便
                    孩子表示法
                        求子節點方便
                    雙親孩子表示法
                        求父節點和子節點都很方便
                    二叉樹表示法
                        把一個普通樹轉化成二叉樹來存儲
                        具體轉換方法:
                            設法保證任意一個節點的
                                左指針域指向它的第一個孩子
                                有指針域指向它的下一個兄弟
                            只要能滿足此條件,就可以把一個普通樹轉化成二叉樹
                            一個普通樹轉化成的二叉樹一定沒有右子樹


                森林的存儲
                    先把森林轉化爲二叉樹,再存儲二叉樹,具體方式爲:根節點
                    之間可以當成是兄弟來看待

            二叉樹操作
                遍歷

                      先序遍歷【先訪問根節點】
                            先訪問根節點
                            再先序訪問左子樹
                            再先序訪問右子樹

                      中序遍歷【中間訪問根節點】
                            中序遍歷左子樹
                            再訪問根節點
                            再中序遍歷右子樹

                      後序遍歷【最後訪問根節點】
                            先後序遍歷左子樹
                            再後序遍歷右子樹
                            再訪問根節點

                  已知兩種遍歷序列求原始二叉樹 
                        通過先序和中序 或者 中序和後續我們可以
                        還原出原始的二叉樹
                        但是通過先序和後續是無法還原出原始的二叉樹的

                        換種說法:
                            只有通過先序和中序, 或通過中序和後序
                            我們纔可以唯一的確定一個二叉樹               

                應用
                    樹是數據庫中數據組織的一種重要形式(例如圖書館
                    的圖書分類一層一層往下分。)
                    操作系統子父進程的關係本身就是一棵樹
                    面嚮對象語言中類的繼承關係本身就是一棵樹
                    赫夫曼樹(樹的一個特例)


    圖

模塊三:查找和排序
        折半查找


        排序:
                冒泡
                插入
                選擇
                快速排序
                歸併排序

        排序和查找的關係
            排序是查找的前提
            排序是重點


Java中容器和數據結構相關知識
    Iterator接口
    Map
        哈希表(與Java關係比較大)

再次討論什麼是數據結構:
    數據結構研究是數據結構的存儲和數據的操作的一門學問
    數據的存儲分爲兩部分:
                個體的存儲
                個體關係的存儲
                從某個角度而言,數據的存儲最核心的就是個體關係
                的存儲,個體的存儲可以忽略不計。

再次討論到底什麼是泛型:
    同一種邏輯結構,無論該邏輯結構物理存儲是什麼樣子的
    我們都可以對它執行相同的操作(例如都是線性結構或者
    用數組實現的樹和用鏈表實現的樹。利用重載技術。)    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章