正文
所謂數(shù)據(jù)存儲(chǔ)結(jié)構(gòu),就是數(shù)據(jù)的元素與元素之間在計(jì)算機(jī)中的一種表示,它的目的是為了解決空間規(guī)模問題,或者是通過空間規(guī)模問題從而間接地解決時(shí)間規(guī)模問題。我們知道,隨著輸入的數(shù)據(jù)量越來越大,在有限的內(nèi)存里,不能把這些數(shù)據(jù)完全的存下來,這就對(duì)數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)和設(shè)計(jì)存儲(chǔ)的算法提出了更高的要求。
本文將介紹幾種存儲(chǔ)結(jié)構(gòu),分別為鏈?zhǔn)浇Y(jié)構(gòu)、樹形結(jié)構(gòu)、圖結(jié)構(gòu)以及矩陣結(jié)構(gòu)。
第一節(jié) 鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)
所謂鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu),一般就是用一個(gè)頭指針指向鏈表的第一個(gè)節(jié)點(diǎn),如果你要增加新的存儲(chǔ)元素時(shí),只需在已有節(jié)點(diǎn)的后面插入新結(jié)點(diǎn)即可。
鏈表通常有單鏈表、雙鏈表、循環(huán)鏈表。在這,我只介紹單鏈表,雙鏈表和循環(huán)鏈表只是單鏈表的拓展罷了。下圖就是一個(gè)簡單的單鏈表圖示。

- typedef char DataType; /***假設(shè)結(jié)點(diǎn)的數(shù)據(jù)域類型為字符***/
- typedef struct node{ /***結(jié)點(diǎn)類型定義***/
- DataType data; /***結(jié)點(diǎn)的數(shù)據(jù)域***/
- struct node *next; /***結(jié)點(diǎn)的指針域***/
- }ListNode;
- typedef ListNode *LinkList;
- ListNode *p;
- LinkList head;
- 附注:
- ① LinkList和ListNode *是不同名字的同一個(gè)指針類型(命名的不同是為了概念上更明確)
- ② LinkList類型的指針變量head表示它是單鏈表的頭指針
- ③ ListNode *類型的指針變量p表示它是指向某一節(jié)點(diǎn)的指針
下面我們來看單鏈表的操作:創(chuàng)建節(jié)點(diǎn)、增加節(jié)點(diǎn)、刪除節(jié)點(diǎn)、查詢、修改。
1.創(chuàng)建節(jié)點(diǎn):聲明一個(gè)節(jié)點(diǎn)并為其申請(qǐng)一段內(nèi)存空間,此節(jié)點(diǎn)有數(shù)據(jù)域和指針域。
- node = (struct List *)malloc(sizeof(struct List));
2.增加節(jié)點(diǎn):插入節(jié)點(diǎn),分為頭插入、尾插入和非頭尾插入。
①. 在表頭插入節(jié)點(diǎn),如圖

- if(p == head) /***其中p為鏈表中的某一節(jié)點(diǎn)***/
- {
- struct list *s = NULL;
- s = (struct list *)malloc(sizeof(struct list)); /***申請(qǐng)空間***/
- s->DataNumber = data; /***為節(jié)點(diǎn)s的數(shù)據(jù)域賦值***/
- /***將節(jié)點(diǎn)s插入表頭***/
- s->next = p;
- head = s;
- }
②. 在表尾插入節(jié)點(diǎn),如圖

- if(p->next == NULL) /***其中p為鏈表中的某一節(jié)點(diǎn)***/
- {
- struct list *s = NULL;
- s = (struct list *)malloc(sizeof(struct list)); /***申請(qǐng)空間***/
- s->DataNumber = data; /***為節(jié)點(diǎn)s的數(shù)據(jù)域賦值***/
- /***將節(jié)點(diǎn)s插入表尾***/
- p->next = s;
- s->next = NULL;
- }
③. 在表中插入非頭尾節(jié)點(diǎn),如圖

- struct list *s = NULL;
- s = (struct list *)malloc(sizeof(struct list)); /***申請(qǐng)空間***/
- s->DataNumber = data; /***為節(jié)點(diǎn)s的數(shù)據(jù)域賦值***/
- /***將節(jié)點(diǎn)s插入表中***/
- s->next = p; /***其中p為鏈表中的某一節(jié)點(diǎn)***/
- q->next = s; /***其中q為鏈表中p節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)***/
3.刪除節(jié)點(diǎn):分為刪除頭結(jié)點(diǎn),刪除尾節(jié)點(diǎn),刪除頭尾節(jié)點(diǎn)。
①. 刪除表頭結(jié)點(diǎn),如圖

- if(p == head) /***p指向鏈表中的某一節(jié)點(diǎn)***/
- {
- head = p->next;
- }
②. 刪除表尾節(jié)點(diǎn),如圖

附注說明:上圖中刪完尾節(jié)點(diǎn)之后,新鏈表的尾節(jié)點(diǎn)下標(biāo)應(yīng)為n-1。不過由于作圖時(shí)只做了尾節(jié)點(diǎn),故用圖中的n2節(jié)點(diǎn)代替。
刪除尾節(jié)點(diǎn)的代碼如下:
- if(p->next == NULL) /***p指向鏈表中的某一節(jié)點(diǎn)***/
- {
- q->next = NULL; /***q指向鏈表中的p節(jié)點(diǎn)的前一節(jié)點(diǎn)**/
- }
③. 刪除非頭尾節(jié)點(diǎn),如圖
刪除非頭尾節(jié)點(diǎn)的代碼如下:
- q->next = p->next; /***p指向鏈表中的某一節(jié)點(diǎn),q指向鏈表中的p節(jié)點(diǎn)的前一節(jié)點(diǎn)***/
4.查詢節(jié)點(diǎn):在鏈表中找到你想要找的那個(gè)節(jié)點(diǎn)。此操作是根據(jù)數(shù)據(jù)域的內(nèi)容來完成的。查詢只能從表頭開始,當(dāng)要找的節(jié)點(diǎn)的數(shù)據(jù)域內(nèi)容與當(dāng)前不相符時(shí),只需讓當(dāng)前節(jié)點(diǎn)指向下一結(jié)點(diǎn)即可,如此這樣,直到找到那個(gè)節(jié)點(diǎn)。
附注:此操作就不在這用圖和代碼說明了。
5.修改節(jié)點(diǎn):修改某個(gè)節(jié)點(diǎn)數(shù)據(jù)域的內(nèi)容。首先查詢到這個(gè)節(jié)點(diǎn),然后對(duì)這個(gè)節(jié)點(diǎn)數(shù)據(jù)域的內(nèi)容進(jìn)行修改。
附注:同上
ok,鏈表的幾種操作介紹完了,接下來我們來總結(jié)一下鏈表的幾個(gè)特點(diǎn)。
鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)的特點(diǎn):
1.易插入,易刪除。不用移動(dòng)節(jié)點(diǎn),只需改變節(jié)點(diǎn)中指針的指向。
2.查詢速度慢:每進(jìn)行一次查詢,都要從表頭開始,速度慢,效率低。
擴(kuò)展閱讀
鏈表:http://public.whut.edu.cn/comptsci/web/data/512.htm
第二節(jié) 樹形存儲(chǔ)結(jié)構(gòu)
所謂樹形存儲(chǔ)結(jié)構(gòu),就是數(shù)據(jù)元素與元素之間存在著一對(duì)多關(guān)系的數(shù)據(jù)結(jié)構(gòu)。在樹形存儲(chǔ)結(jié)構(gòu)中,樹的根節(jié)點(diǎn)沒有前驅(qū)結(jié)點(diǎn),其余的每個(gè)節(jié)點(diǎn)有且只有一個(gè)前驅(qū)結(jié)點(diǎn),除葉子結(jié)點(diǎn)沒有后續(xù)節(jié)點(diǎn)外,其他節(jié)點(diǎn)的后續(xù)節(jié)點(diǎn)可以有一個(gè)或者多個(gè)。
如下圖就是一棵簡單的樹形結(jié)構(gòu):
說到樹形結(jié)構(gòu),我們最先想到的就是二叉樹。我們常常利用二叉樹這種結(jié)構(gòu)來解決一些算法方面的問題,比如堆排序、二分檢索等。所以在樹形結(jié)構(gòu)這節(jié)我只重點(diǎn)詳解二叉樹結(jié)構(gòu)。那么二叉樹到底是怎樣的呢?如下圖就是一顆簡單的二叉樹:
附注:有關(guān)樹的概念以及一些性質(zhì)在此不做解釋,有意者請(qǐng)到百科一覽。
二叉樹的類型描述如下:
- typedef struct tree
- {
- char data;
- struct tree * lchild, * rchild; /***左右孩子指針***/
- }tree;
二叉樹的操作:創(chuàng)建節(jié)二叉樹,創(chuàng)建節(jié)點(diǎn),遍歷二叉樹,求二叉樹的深度。
1.創(chuàng)建二叉樹:聲明一棵樹并為其申請(qǐng)存儲(chǔ)空間。
- struct tree * T = NULL;
- T = (struct tree *)malloc(sizeof(struct tree));
2.創(chuàng)建節(jié)點(diǎn):除根節(jié)點(diǎn)之外,二叉樹的節(jié)點(diǎn)有左右節(jié)點(diǎn)之分。
創(chuàng)建節(jié)點(diǎn)的代碼如下:
- struct tree * createTree()
- {
- char NodeData;
- scanf(" %c", &NodeData);
- if(NodeData == '#')
- return NULL;
- else
- {
- struct tree * T = NULL;
- T = (struct tree *)malloc(sizeof(struct tree));
- T->data = NodeData;
- T->lchild = createTree();
- T->rchild = createTree();
- return T;
- }
- }
3.遍歷二叉樹:分為先序遍歷、中序遍歷、后續(xù)遍歷。
①.先序遍歷:若二叉樹非空,則依次執(zhí)行如下操作:
(1) 訪問根結(jié)點(diǎn);
(2) 遍歷左子樹;
(3) 遍歷右子樹。
如圖:
先序遍歷的代碼如下:
- void PreTravser(struct tree * T)
- {
- if(T == NULL)
- return;
- else
- {
- printf("%c",T->data);
- PreTravser(T->lchild);
- PreTravser(T->rchild);
- }
- }
②.中序遍歷:若二叉樹非空,則依次執(zhí)行如下操作:
(1)遍歷左子樹;
(2)訪問根結(jié)點(diǎn);
(3)遍歷右子樹。
如圖:
中序遍歷的代碼如下:
- void MidTravser(struct tree * T)
- {
- if(!T)
- {
- return;
- }
- else
- {
- MidTravser(T->lchild);
- printf("%c",T->data);
- MidTravser(T->rchild);
- }
- }
③.后續(xù)遍歷:若二叉樹非空,則依次執(zhí)行如下操作:
(1)遍歷左子樹;
(2)遍歷右子樹;
(3)訪問根結(jié)點(diǎn)。
如圖:

- void PostTravser(struct tree * T)
- {
- if(!T)
- return;
- else
- {
- PostTravser(T->lchild);
- PostTravser(T->rchild);
- printf("%c->",T->data);
- }
- }
4.求二叉樹的深度:樹中所有結(jié)點(diǎn)層次的最大值,也稱高度。
二叉樹的深度表示如下圖:

- int treeDeepth(struct tree * T)
- {
- int i, j;
- if(!T)
- return 0;
- else
- {
- if(T->lchild)
- i = treeDeepth(T->lchild);
- else
- i = 0;
- if(T->rchild)
- j = treeDeepth(T->rchild);
- else
- j = 0;
- }
- return i > j? i+1:j+1;
- }
好了,二叉樹的幾種操作介紹完了。
拓展閱讀
二叉樹:http://student.zjzk.cn/course_ware/data_structure/web/DOWNLOAD/%CA%FD%BE%DD%BD%E1%B9%B9%D3%EB%CB%E3%B7%A82.htm
赫夫曼編碼:http://blog.csdn.net/fengchaokobe/article/details/6969217
第三節(jié) 圖型存儲(chǔ)結(jié)構(gòu)
所謂圖形結(jié)構(gòu),就是數(shù)據(jù)元素與元素之間的關(guān)系是任意的,任意兩個(gè)元素之間均可相關(guān),即每個(gè)節(jié)點(diǎn)可能有多個(gè)前驅(qū)結(jié)點(diǎn)和多個(gè)后繼結(jié)點(diǎn),因此圖形結(jié)構(gòu)的存儲(chǔ)一般是采用鏈接的方式。圖分為有向圖和無向圖兩種結(jié)構(gòu),如下圖


1.圖的結(jié)構(gòu)有好幾種,在實(shí)際應(yīng)用中需根據(jù)具體的情況選擇合適的結(jié)點(diǎn)結(jié)構(gòu)和表結(jié)構(gòu)。常用的有數(shù)組結(jié)構(gòu)、鄰接表。
①.數(shù)組結(jié)構(gòu)
數(shù)組結(jié)構(gòu)的類型描述如下:
- typedef char VertexType; /***頂點(diǎn)類型***/
- typedef int EdgeType; /***邊權(quán)值類型***/
- #define maxvex 100 /***頂點(diǎn)的最大個(gè)數(shù)***/
- typedef struct
- {
- VertexType vexs[maxvex]; /***頂點(diǎn)個(gè)數(shù)***/
- EdgeType arc[maxvex][maxvex]; /***兩頂點(diǎn)構(gòu)成邊的權(quán)值***/
- }Mgraph;
②.鄰接表
鄰接表的類型描述如下:
- typedef char VertexType; // 頂點(diǎn)類型
- typedef int EdgeType; //邊權(quán)值類型
- typedef struct EdgeNode //邊表節(jié)點(diǎn)
- {
- int adjvex; //鄰接點(diǎn)域,存儲(chǔ)該頂點(diǎn)對(duì)應(yīng)的下標(biāo)
- EdgeType weight; //用于存儲(chǔ)權(quán)值
- struct EdgeNode *next; //鏈域,指向下一個(gè)鄰接點(diǎn)
- }EdgeNode;
- typedef struct VertexNode //頂點(diǎn)表節(jié)點(diǎn)
- {
- VertexType data; //頂點(diǎn)域,存儲(chǔ)頂點(diǎn)信息
- EdgeNode * firstedge; //邊表頭指針
- }VertexNode,AdjList[MAXVEX];
- typedef struct
- {
- AdjList adjList;
- int numVertexes,numEdges; //圖當(dāng)前頂點(diǎn)數(shù)和邊數(shù)
- }GraphAdjList;
2.圖的遍歷:從圖中的某一節(jié)點(diǎn)出發(fā)訪問圖中的其余節(jié)點(diǎn),且使每一節(jié)點(diǎn)僅被訪問一次。圖的遍歷算法是求解圖的連通性問題、拓?fù)渑判蚝颓舐窂降人惴ǖ幕A(chǔ)。圖的遍歷分為深度優(yōu)先遍歷和廣度優(yōu)先遍歷,且它們對(duì)無向圖和有向圖均適用。
①. 深度優(yōu)先遍歷
定義說明:假設(shè)給定圖G的初態(tài)是所有頂點(diǎn)均未曾訪問過。在G中任選一頂點(diǎn)V為初始出發(fā)點(diǎn),則深度優(yōu)先遍歷可定義如下:首先訪問出發(fā)點(diǎn)V,并將其標(biāo)記為已訪問過;然后依次從V出發(fā)搜索v的每個(gè)鄰接點(diǎn)W。若W未曾訪問過,則以W為新的出發(fā)點(diǎn)繼續(xù)進(jìn)行深度優(yōu)先遍歷,直至圖中所有和源點(diǎn)V有路徑相通的頂點(diǎn)(亦稱為從源點(diǎn)可達(dá)的頂點(diǎn))均已被訪問為止。若此時(shí)圖中仍有未訪問的頂點(diǎn),則另選一個(gè)尚未訪問的頂點(diǎn)作為新的源點(diǎn)重復(fù)上述過程,直至圖中所有頂點(diǎn)均已被訪問為止。
深度遍歷過程如下圖:

②. 廣度優(yōu)先遍歷
定義說明:假設(shè)從圖中某頂點(diǎn)V出發(fā),在訪問了V之后一次訪問V的各個(gè)未曾訪問過的鄰接點(diǎn),然后分別從這些鄰接點(diǎn)出發(fā)依次訪問它們的鄰接點(diǎn),并使“先被訪問的頂點(diǎn)的鄰接點(diǎn)”先于“后被訪問的頂點(diǎn)的鄰接點(diǎn)”被訪問,直至圖中所有已被訪問的頂點(diǎn)的鄰接點(diǎn)都被訪問到。若此時(shí)圖中還有頂點(diǎn)未被訪問,則另選圖中一個(gè)未曾被訪問的頂點(diǎn)作為起始點(diǎn),重復(fù)上述過程,直至圖中所有頂點(diǎn)都被訪問到為止。換句話說,廣度優(yōu)先遍歷圖的過程是以V為起點(diǎn),由近至遠(yuǎn),依次訪問和V有路徑相同且路徑長度為1,2,...的頂點(diǎn)。
廣度遍歷過程如下圖:

擴(kuò)展閱讀
最小生成樹:Prim算法,Kruskal算法
最短路徑:Dijkstra算法,F(xiàn)loyd算法
第四節(jié) 結(jié)束語
想想,寫寫,畫畫......
原文地址:http://blog.csdn.net/fengchaokobe/article/details/7416547