資料結構研究的是:我們如何把現實中大量而複雜的問題以特定的資料型別和特定的儲存結構儲存到主儲存器(記憶體)中,以及在此基礎上為實現某個功能(比如查詢、刪除某個元素)而執行的相應操作(這個操作也叫做演算法)
總得來說,資料結構研究的是資料的儲存和對資料的操作。
其中,資料的儲存包括資料個體的儲存、個體間關係的儲存,我們認為個體關係的儲存更為重要,系資料結構所要研究的乙個重點。
既然要研究資料的儲存,那麼我們就需要創造一些儲存結構,這些儲存結構既要能夠滿足儲存需求,又要方便儲存資料之間的關係。
我們將儲存結構分為線性結構和非線性結構,劃分的依據為結構是否為一維的。其中,線性結構包括陣列、鍊錶,非線性結構包括樹和圖。對於線性結構,其常見應用為棧和佇列。這裡我主要詳細學習了鍊錶、棧、佇列,粗略學習了樹。
在正式學習資料結構之前,需要預備和鞏固一些c語言的知識,如指標、結構體、動態記憶體的分配:
指標是c語言的靈魂,有強大的用處,且所有指標變數只佔4個位元組。指標變數是存放記憶體單元位址的變數,或者說,指標就是位址,位址就是指標。我個人覺得對於指標,心中一定要有這樣的概念:
指標可以用於傳入函式並取出函式中的某個數值、而結構體則是為了表示一些複雜的資料(普通的基本變數型別無法滿足需求)。能熟悉結構體的基本操作就行了,諸如訪問其成員變數之類的。傳指標比傳入整個結構更方便、
通過對指標的操作能夠間接對該指標指向的某個變數進行操作
研究動態記憶體分配有以下幾個原因
可以通過malloc得到一塊記憶體空間,並以此方法得到大量(許多塊)離散的空間。那麼我們就可以通過malloc來模擬一些離散結構或者連續結構。有了這些簡單的理解就可以開始學習資料結構了。函式呼叫中,子函式生成的變數存在作用域,所生成的變數是靜態的,有生存期,而malloc生成的記憶體空間只要沒有free掉,就是一直存在的,動態的。那麼我們就可以通過malloc生成一些不被自動清除的儲存結構。
這個沒啥好說的,都已經會了。
由於有時候我們無法得到一塊較大且連續的記憶體空間,但是我們可以得到同樣記憶體大小只不過是離散的空間。於是有了鍊錶。
鍊錶簡單來說就是先定義乙個個"節點"的儲存結構,然後用指標把這些結構依次聯絡起來,得到一條線性的鏈,即為鍊錶。具體的定義為:
n個節點離散分配,彼此通過指標相連,每個節點只有乙個前驅節點和乙個後續節點,首節點沒有前驅節點,尾結點沒有後續節點於是我們就要研究如何去構建乙個"節點"的儲存結構:定義乙個結構體,其中包含乙個資料域和乙個指標域,資料域可以是簡單的乙個int型的資料,也可以是複雜的。指標域可以是兩個指標,用於指向該節點的前後兩個節點,也可以只用乙個指標,指向該節點的後續節點。(兩個指標的那種稱為雙向鍊錶,乙個指標的為單向鍊錶,這裡我們只以單向鍊錶為例)
//建立乙個結構體來表示單鏈表的節點
typedef
struct node
node,
*pnode;
//node等價於 struct node,pnode等價於struct node *
注意這裡指標的型別也是乙個節點node型別,因為該指標待指向的就是node型別的節點,所以儲存的也是node型別的位址,自然用的是node *。
這裡要提到一點,在首節點前,還有乙個頭節點,不存放有效資料,只是為了方便鍊錶的一些操作。
於是通過指向煉表頭節點的指標,我們就可以獲取到整個鍊錶。但是,由於是單鏈表,我們要對鍊錶進行某些操作(插入節點、刪除節點)時,必須從頭開始往後遍歷。
具體**見附帶檔案。
棧是在鍊錶的基礎上形成的一種儲存結構,可以理解為一種容器,一種可以實現「先進後出」的儲存結構,類似於子彈彈夾。
棧這種儲存型別簡單來說就是定義兩個指標,用來表示棧頂和棧底,然後用節點去填充這個棧,每填充乙個節點,該節點的指標指向先前的棧頂的節點,同時,指向棧頂的指標跟著移位指向新的棧頂。
具體**定義如下:
typedef
struct stack
stack,
*pstack;
//stack等價於 struct stack,pstack等價於struct stack *
這裡可以這樣理解,其實棧只是提供了兩塊鐵片,實際儲存單元還是節點,我們只不過用這兩塊鐵片分別放在這些節點的頂部和底部,"方便"我們操作而已。所以我們可以把棧看做是操作受限的鍊錶(只能從棧頂對其進行操作),諸如壓棧、出棧其實就是鍊錶的增加乙個節點和刪除乙個節點的操作,只不過多了兩個棧指標,所以稍微複雜了一些。
棧遵循"先進後出",或者說"後進先出",具體應用有諸如函式呼叫、中斷、記憶體分配等。
具體**見附帶檔案。
佇列是一種可以實現「先進先出」的儲存結構。
這裡以靜態隊列為例,用陣列實現。(鏈式佇列——用鍊錶實現,這裡不談,但是佇列是鍊錶的常用應用)
靜態佇列為了避免記憶體空間的浪費,通常都採用迴圈佇列。於是我們可以把佇列想象成乙個輪盤、乙個左***的子彈槽。與棧類似,我們有兩個指標,乙個用於指向新增添的元素的下一位,乙個用於指向新刪去的元素的下一位。
一開始,兩個指標同時指向起始位置(陣列下標設為零)。每增加乙個元素(即增加節點),存放在名為rear的指標所指向的位置,且rear指向下一位。每刪除乙個元素(即刪除節點),刪除名為front的指標所指向位置的節點,且front指向下一位。則front和rear就在元素增減的過程中追趕。由於是迴圈佇列,所以整個"轉盤"一直轉圈,記憶體空間恆定,不會存在記憶體洩露或者浪費的問題。
同時,我們也能發現,我們只能從rear所在位置增加元素,只能從front所在位置刪除元素,先進入的節點最接近front最先被刪除,是一種"先進先出"的結構。而且它其實也是一種操作受限的鍊錶。
由於是先進先出,所以所有和時間有關的操作都有佇列的影子,根據時間順序先幹嘛後幹嘛…
其定義是乙個函式直接或間接呼叫自己。
遞迴的思想個人總結為:任務複雜,能力不足,任務下推
即,儘管任務很龐大,我只管處理我所能夠處理的最小一部分,其餘部分交給"另乙個未來的我"去處理。
或者說,乙個任務實現的前提,是完成乙個難度稍微降低的同一任務,且存在乙個最底層的任務能夠輕易完成。
遞迴的應用:樹和森林就是以遞迴的方式定義的,樹和圖的很多演算法都是以遞迴來實現的
非線性結構包括樹和圖,只學了樹,這裡只討論二叉樹。
其實和前面的鍊錶差不多的是,基礎結構還是節點,只不過這個節點的指標域需要有兩個指標,用來指向左孩子和右孩子節點。然後類似鍊錶,通過指標鏈結起來就行了。
這裡,我們回顧對比一下之前的鍊錶、棧、佇列。
我們之前提到,資料儲存中,我們認為個體關係的儲存更為重要,系資料結構所要研究的乙個重點。
這裡樹是非線性結構,各個節點之間的關係不是一維的,不是單純的線性。這樣的話,樹的儲存會有什麼不同嗎?或者說,我們又如何處理各個節點的關係呢?
其實這個問題我們在生成樹的基本單元——節點——的時候,就已經解決了。每個節點都存放著兩個指標,指向該節點的孩子節點。只要指標指好了,個體關係就確定好了。那麼雖然說各個節點是離散的,只管存放就是了,節點的關係已經儲存在每個節點中了。
也就是說,儘管我們每個節點可能是按照隨意順序存放的,但是只要拿出來,還是一整棵完整的樹,關係通過存放在節點中的指標儲存。
接下來又有乙個問題,個體間關係是儲存起來了,我們怎麼表現出來呢?如果我們羅列出樹的所有元素,我們怎麼把關係也同時展示出來呢?
我們知道樹是非線性的結構,如果我們把這些節點拍成一排,變成線性的一維結構,就要想辦法用一種順序來確定他們的關係。於是就有了先序遍歷、中序遍歷和後序遍歷。通過以上三種遍歷方式的其中一種,可以把整棵樹轉換成一維線性的結構輸出,通過以上三種便利方式的中序遍歷以及剩餘任意一種,可以將一維線性的這種結構還原成原本的非線性的樹的結構(關係)。
以上。學習途徑: b站郝斌資料結構
資料結構學習總結
了解資料,資料項,資料元素,資料物件的關係。資料元素 組成資料的,具有一定意義的基本單位,在計算機中做整體處理,也稱為記錄。乙個資料元素可以由多個資料項組成。資料物件 資料相同的資料元素的集合,是資料的子集。有的書上也成為資料物件和例項,結合的理解。資料結構可以分為 物理結構和邏輯結構 邏輯結構 集...
資料結構學習總結
隨著2015年的結束,資料結構這門課程也即將結束,這乙個學期跟著賀老師一起通過翻轉課堂的方式學習既新鮮也很慶幸。對這一學期資料結構的學習我想說一說我的感受。這學期資料結構 學了線性結構 樹 圖等等 線性結構包括線性表 棧 佇列 串 陣列 廣義表等 遞迴是程式設計中很重要的一種工具 也是我需要掌握的乙...
資料結構學習總結
第一章是緒論,介紹了資料結構的基本概念,資料結構有邏輯結構和儲存結構兩種 第二章為線性表,介紹了線性表的兩種儲存結構 順序表和煉表與其基本運算演算法的實現,鍊錶又包括單鏈表 雙鏈表 迴圈列表等多種形式 第三章為棧和佇列,介紹這兩種特殊的線性結構的概念與應用 第四章是串,介紹串,包括順序串和鏈串的概念...