數據結構學習有感

雜談

這兩天已經開始看數據結構了,儘管c語言還是懵懵懂懂。我學習的課本是 嚴蔚敏老師的《數據結構》(c語言版)。其實我數買了一段時間,但是一直摸有開始,原因很簡單,看不懂結構體。經常看到一大堆莫名其妙的引用 訪問什麼的,瞬間頭大。所以我就抽時間去吧結構體學了一下。 學完結構體我尋思着,可以看看看數據結構了吧,我還是太年輕了。
數據結構 主要是數據和數據之間的關係 以及存儲形式(我目前的認知)。單說書上的結構,概念其實很簡單,數據之間的關係一講其實也就全都明白了。但是,我覺得這本書確實有點難學。因爲書上有很多算法知識(我的感覺)。我們把數據 和數據之間的關係用特定的方式存儲進來,要實現某種目標,就必須用某種方法來對這些數據進行有效的推導、計算、剖析等。就拿一個很簡單的 表達式求值來說。要用棧結構,這個我知道,但是如何把表達式存入,又如何取出,最後又如何計算呢?他並不是無腦的讀一個、壓一個。書上的例子卸載哪裏,我卻看不懂,最後去問百度爸爸,才知道中間涉及到一箇中綴轉後綴的過程。還有一道書上的字符串模式匹配的例子。

那個next數組的求法,以及意義很簡單,我可以通過手工算出來,無非就是字符串前綴模式和後綴模式相同時最大字符串長。

但是如何通過編程讓機器去運算的。 我逐漸發現,一旦將某些簡單問題的規模擴大化,雖然原始的解決方法同樣適用,但是從計算成本上來就顯得並不合適。我們就需要通過某種具有數學歸納思想的解決辦法,將同種問題不同規模的解決辦法歸納成一個模板。最後只要套用模板,由計算機去代替人力運算,就能得到結果。

這個模板就是我所理解的泛型

而對複雜問題的巧妙解決中間所涉及的數學思想,邏輯能力就是我目前所認知的算法。

結構體

學習數據結構就必須要對結構體有一個基本的掌握。因爲在往常的數據類型中,並沒有一種結構能夠包含多種不同類型數據。而數據結構,主要是數據和數據之間的關係,而實際情況看往往是複數、複雜、的數據之間相互關聯。所以結構體就是數據結構的首選,結構體就是數據結構的基本組成單位(我的個人理解)。

結構體聲明

關鍵字 struct + 類型名稱
{
內部數據類型(數組 、int、char、等)
}+變量名;

例如
定義一個學生的基本信息結構體

typedef struct Stu
 { 
   char name[20];//名字  
   int age;//年齡   
   char sex[5];//性別 
   char id[20]//學號 
}Stu2;//分號不能

結構體 的類型名稱(struct 後面的變量名 例如 struct Stu中的Stu)可以省略。結構體變量的變量名稱也可以省略。(例如上述的Stu2)但是兩者必須要有一個。

結構體成員訪問

結構體成員訪問有兩種訪問方式。一種是結構體變量名稱.訪問成員一種是結構體指針->訪問成員

struct Stu {
    char name[20]; 
    int age; 
}*ps;

(*ps).name     (*ps).age; 

 ps->name,       ps->age ; 

結構體中可以嵌套結構體,訪問嵌套結構體時,按照上述規則訪問即可。

結構體傳參

結構體傳參和數組傳參不一樣

數組傳參會發生降維問題。但是結構體不會發生。
結構體在傳參時,如果傳入的實參時結構體變量時,,在發生形參實例化時,會發生結構體全拷貝。並不會和數組一樣降維成對應的指針。
傳入結構體實參會發生全拷貝,造成不必要的內存耗費,既然上述已經說過結構體成員的訪問形式有兩種,指針也可以對結構體進行成員訪問,切指針在傳參時,哪怕發生拷貝,拷貝的也只是一個指針大小,並不會造成內存的浪費。所以在大多數情況下結構體傳參一般傳入的都是結構體指針。

內存問題

數據結構中很多內存都是在堆上開配的空間,很多時候都會用到開闢內存的函數

melloc函數

其函數原型爲void *malloc(unsigned int size);其作用是在內存的動態存儲區中分配一個長度爲size的連續空間。此函數的返回值是分配區域的起始地址,或者說,此函數是一個指針型函數,返回的指針指向該分配域的開頭位置。

在使用melloc函數時元注意,我們需要對melloc函數的返回值進行強制類型轉換。如果不做強制類型轉換的話,返回的指針和需要的指針類型不一樣,就會對訪問造成影響。並且如果有後續的存儲操作一般都需要對melloc函數的返回值進行判斷避免開闢空間失敗的情況。

relloc函數

realloc(void *__ptr, size_t __size):更改已經配置的內存空間,即更改由malloc()函數分配的內存空間的大小。

如果將分配的內存減少,realloc僅僅是改變索引的信息。

如果是將分配的內存擴大,則有以下情況:

1)如果當前內存段後面有需要的內存空間,則直接擴展這段內存空間,realloc()將返回原指針。
2)如果當前內存段後面的空閒字節不夠,那麼就使用堆中的第一個能夠滿足這一要求的內存塊,將目前的數據複製到新的位置,並將原來的數據塊釋放掉,返回新的內存塊位置。
3)如果申請失敗,將返回NULL,此時,原來的指針仍然有效。

原文鏈接:https://blog.csdn.net/hackerain/article/details/7954006

其中第二點是先在堆上找到一段空閒內存,開闢需求內存擴大之後的空間。然後將原來那段內存中的數據完全 copy過來。最後原來那段空間會自動釋放,並不需要手動free

free函數

C 庫函數 void free(voidptr)* 釋放之前調用 calloc、malloc 或 realloc 所分配的內存空間 [1] 。

free函數看起來很簡單。但是在實際使用過程中,書上一般會先聲明一個和目標指針相同類型的結構體指針,然後對這個新聲明的結構體指針進行賦值(將目標指針作爲右值)。最後再由free函數釋放。
例如

struct  A *a//定義一個新的結構體指針
a=b//b爲目標指針
free(a);

一般都是這種形式的釋放。至於爲什麼要這樣我到現在也不是很懂。

melloc函數開闢的動態內存一般都要通過free函數釋放。如果不釋放就會造成內存泄漏的問題。
同時melloc函數free函數中所有指針類型一定要統一(melloc函數返回指針要進行強制類型轉換,free函數的實參指針類型一定要統一)

以上就是我近期的學習想法。可能有很多錯誤,希望大佬們指正

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章