重拾數據結構

這裏主要是記錄各類數據結構的結構體, 對於具體實現和講解往後回會以連接形式提供, 這裏只提供一個思惟樹, 創建一個數據結構的思惟體系, 後續更新歡迎關注 GitHub.node

1 線性表

1.1 動態分配空間
typedef struct {
    ElemType * elem;
    int length;
    int listsize;
} SqList;複製代碼
1.2 線性鏈表
typedef struct LNode {
    ElemType data;
    struct LNode * next;
} LNode, * LinkList;複製代碼
1.3 靜態鏈表
typedef struct {
    ElemType data;
    int cur;    // 遊標指向下一個元素的數組下標
} component, SlinkList[MAXSIZE];複製代碼
1.4 循環鏈表 & 雙向鏈表
typedef struct DuLNode{
    ElemType data;
    struct DuLNode * prior;
    struct DuLNode * next;
} DuLNode, * DuLinkList;複製代碼

2 棧和隊列

2.1 棧
typedef struct {
    SELemType * base;
    SElemType * top;##### int stacksize;
} SqStack;複製代碼

應用: 主要是利用先進後出的特性git

  • 數制轉換github

  • 括號匹配檢測面試

  • 行編輯程序算法

  • 迷宮非遞歸求解數組

  • 表達式求值數據結構

  • Hanoi塔問題curl

2.2 隊列
  • 鏈隊列
typedef struct QNode {
    QElemType data;
    struct QNode * next;
} QNode, * QueuePtr;
typedef struct {
    QueuePtr front;
    QueuePtr rear;
} LinkQueue;複製代碼
  • 循環隊列
typedef struct {
    QElemType * base;
    int front;
    int rear;
} SqQueue;複製代碼

3 串

3.1 定長串
typedef unsigned char SString[MAXSTRLEN + 1];
SString s;複製代碼
3.2 變長
  • 堆分配存儲
typedef struct {
    char * ch;
    int length;
}HString;複製代碼
  • 塊鏈存儲
typedef struct Chunk{
    char ch[CHUNKSIZE];
    struct Chunk * next;
} Chunk;
typedef struct {
    Chunk * head;
    Chunk * tail;
    int curlen;
} LString;複製代碼

應用函數

  • 子串定位 (KMP)

4 數組和廣義表

4.1 數組順序存儲
typedef struct {
    ElemType * base;
    int dim;    // 數組維數
    int * bounds;    // 維界基址
    int * constants;    // 印象函數常量基址
} Array;複製代碼
4.2 矩陣

討論稀疏矩陣的存儲優化

  • 三元順序表
typedef struct {
    int i;
    int j;
    ElemType e;
} Triple;
typedef struct {
    Triple data[MAXSIZE + 1];
    int mu;    // 行
    int nu;    // 列
    int tu;    // 非零個數
}TSMatrix;複製代碼
  • 行邏輯連接
typedef struct {
    Triple data[MAXSIZE + 1];
    int rpos[MAXRC + 1];    // 各行第一個非零元素位置表
    int mu, nu, tu;
} RLSMatrix;複製代碼
  • 十字鏈表
typedef struct OLNode {
    int i;
    int j;
    ElemType e;
    struct OLNode * right;    // 該非零元素所在行的右鏈域
    struct OLNode * down;    // 該非零元素所在列的下鏈域
} OLNode, * OLink;
typedef struct {
    OLink * rhead;    // 行鏈表頭指針地址
    OLink * chead;    // 列鏈表頭指針地址
    int mu, nu, tu;
} CrossLink;複製代碼
4.3 廣義表

表中有表

  • 頭尾鏈表存儲
typedef enum { ATOM, LIST } ElemTag;    // 0 : 原子, 1 : 子表
typedef struct GLNode {
    ElemTag tag;
    union {
        AtomType atom;
        struct {
            struct GLNode * hp;    // 表頭
            struct GLNode * tp;    // 表尾
        } ptr;    // 表節點指針域
    };
} * GList;複製代碼
  • 擴展線性鏈表存儲
typedef enum { ATOM, LIST } ElemTag;    // 0 : 原子, 1 : 子表
typedef struct GLNode {
    ElemTag tag;
    union {
        AtomType atom;
        struct {
            struct GLNode * hp;    // 表頭
        } ptr;    // 表節點指針域
    };
    struct GLNode * tp;    // 表尾, 至關於 next.
} * GList;複製代碼

5 樹和二叉樹

5.1 二叉樹存儲結構
  • 順序存儲結構

數組, 利用下標尋址

typedef TElemType SqBiTree[MAX_TREE_SIZE];複製代碼
  • 鏈式存儲結構
typedef struct BiTNode {
    TElemType data;
    struct BiTNode * lchild;
    struct BiTNode * rchild;
} BiTNode, * BiTree;複製代碼
5.2 遍歷二叉樹
  • 先序遍歷

根節點 -> 左子樹 -> 右子樹

  • 中序遍歷

左子樹 -> 根節點 -> 右子樹

  • 後序遍歷

左子樹 -> 右子樹 -> 根節點

算數表達式 a + b * (c - d) - e / f

前綴表達式-先序遍歷(逆波蘭 : - + a * b - cd / ef)

中綴表達式-中序遍歷(原表達式 : a + b * (c - d) - e / f)

後綴表達式-後續遍歷(逆波蘭式 : abcd - * + ef / -)

5.3 線索二叉樹

保存比遍歷過程當中的節點相關性結果

前驅後繼節點和左右孩子指示

lchild LTag data RTag rchild

LTag 0 : lchild 域指示左孩子 1 : lchild 域指示前驅節點

RTag 0 : rchild 域指示右孩子 1 : rchild 域指示後繼節點

typedef enum PointerTag {Link, Thread};    // 0 : 指針 1 : 線索
typedef struct BiThrNode {
    TElemType data;
    struct BiThrNode * lchild;
    struct BiThrNode * rchild;
    PointerTag LTag;
    PointerTag RTag;
} BiThrNode, * BiThrTree;複製代碼
5.4 樹和森林
  • 雙親表示法
typedef struct PTNode {
    TElemType data;
    int parent;
} PTNode;
typedef struct {
    PTNode nodes[MAX_TREE_SIZE];
    int r;    // 根的位置
    int n;    // 節點數
} PTree;複製代碼
  • 孩子表示法
typedef struct CTNode {    // 孩子節點
    struct CTNode * next;
    int child;
} * ChildPtr;
typedef struct {
    TElemType data;
    ChildPtr firstchild;    // 孩子鏈表頭指針
} CTBox;
typedef struct {
    CTBox nodes[MAX_TREE_SIZE];
    int r;    // 根的位置
    int n;    // 節點數
} CTree;複製代碼
  • 孩子兄弟表示法
typedef struct CSNode {
    ElemType data;
    struct CSNode * firstchild;
    struct CSNode * nextsibling;
} CSNode, * CSTree;複製代碼
5.5 二叉樹和森林互換
  • 森林轉換成二叉樹

左孩子右兄弟(左右是對二叉樹而言, 孩子兄弟是對森林而言, 下面同理)

  • 二叉樹轉換成森林

左孩子轉換成孩子, 右孩子轉換成兄弟

5.6 樹和森林遍歷
  • 先序遍歷森林
  1. 第一棵樹的根

  2. 先序遍歷第一棵樹中根節點的子樹森林

  3. 先序遍歷除第一棵樹剩餘的樹構成的森林

  • 中序遍歷森林
  1. 中序遍歷第一棵樹中根節點的子樹森林

  2. 第一棵樹的根

  3. 中序遍歷除第一棵樹剩餘的樹構成的森林

7 圖

7.1 圖的存儲結構
  • 數組表示法
typedef enum {DG, DN, UDG, UDN} GraphKind;    // {有向圖, 有向網, 無向圖, 無向網}
typedef struct ArcCell {
    VRType adj;    // 頂點相關類型. 無權圖 : 1/0 表示相鄰與否 帶權圖 : 權值信息
    InfoType * info;    // 該弧相關的指針
} ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct {
    VertexType vexs[MAX_VERTEX_NUM];    // 頂點向量
    AdjMatrix arcs;    // 鄰接矩陣
    int vexnum;    // 頂點數
    int arcnum;    // 弧數
    GraphKind kind;    // 圖的種類標誌
} MGraph;複製代碼
  • 鄰接表

表節點

adjvex nextarc info

頭結點

data firstarc
typedef struct ArcNode {
    int adjvex;    // 該弧所指向頂點位置
    struct ArcNode * nextarc;    // 指向下一條弧的指針
    InfoType * info;    // 該弧相關信息的指針
} ArcNode;
typedef struct VNode {
    VertexType data;    // 頂點信息
    ArcNode * firstarc;    // 指向第一條依附該頂點的弧的指針
} VNode, AdjList[MAX_VERTEX_NUM];
typedef struct {
    AdjList vertices;
    int vexnum;    // 頂點數
    int arcnum;    // 弧數
    int kind;    // 種類標記
} ALGraph;複製代碼
  • 十字鏈表

弧節點

tailvex headvex hlink tlink info

頂點節點

data firstin firstout
typedef struct ArcBox {
    int tailvex;    // 該弧的尾頂點位置
    int headvex;    // 該弧的頭頂點位置
    struct ArcBox * hlink;    // 弧頭相同的弧的鏈域
    struct ArcBox * tlink;    // 弧尾相同的弧的鏈域
    InfoType * info;    // 該弧相關信息指針
} ArcBox;
typedef struct VexNode {
    VertexType data;
    ArcBox * firstin;    // 指向該節點第一條入弧
    ArcBox * firstout;    // 指向該節點第一條出弧
} VexNode;
typedef struct {
    VexNode xlist[MAX_VERTEX_NUM];    // 表頭向量
    int vexnum;    // 有向圖的當前頂點數
    int arcnum;    // 有向圖的當前弧數
} OLGraph;複製代碼
  • 鄰接多重表

每一條邊用一個節點表示

mark ivex ilink jvex jlink info

每一個頂點用一個節點表示

data firstedge
typedef enum {unvisited, visited} VisitIf;
typedef struct EBox {
    VisitIf mark;    // 訪問標記
    int ivex;    // 依附頂點位置
    int jvex;    // 依附頂點位置
    struct EBox * ilink;    // 依附頂點的下一邊
    struct EBox * jlink;    // 依附頂點的下一邊
    InfoType * info;    // 該邊的信息指針
} EBox;
typedef struct VexBox {
    VertexType data;
    EBox * firstedge;    // 指向第一條依附該頂點的邊
} VexBox;
typedef struct {
    VexBox adjmulist[MAX_VERTEX_NUM];
    int vexnum;    // 無向圖的頂點數
    int edgenum;    // 無向圖的邊數
} AMLGraph複製代碼
7.2 圖的遍歷
  • 深度優先搜索

以迷宮爲例子(面試中被問到, 印象比較深入). 深度優先就是一條路走到黑, 因此返回的第一條路徑不保證是最優解.

Boolean visited[MAX];    // 訪問標誌數組
Status (* VisiteFunc) (int v);    // 韓阿叔變量

void DFSTraverse(Graph G, Status (* Visit)(int v)) {    // 深度優先遍歷
    VisitFunc = Visit;    // 使用全局變量 VisitFunc, 使 DFS 沒必要設置函數指針參數
    for (v = 0; v < G.vexnum; ++v) {
        visited[v] = FALSE;    // 訪問數組標誌初始化
    }
    for (v = 0; v < G.vexnum; ++v) {
        if (!visited[v]) {
            DFS(G, v);    // 對未訪問的頂點調用 DFS
        }
    }
}

void DFS(Graph G, int v) {    // 從第 v 個頂點出發遞歸的深度優先遍歷圖 G.
    visited[v] = TRUE;
    VisitFunc(v);    // 訪問第 v 個頂點
    for (w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w)) {
        if (!visited[w]) {
            DFS(G, w);    // 對 v 的還沒有訪問的鄰接頂點 w 遞歸調用 DFS.
        }
    }
}複製代碼
  • 廣度優先搜索

有點層序遍歷的意思, 在遍歷完全部狀況下(能夠進行算法優化, 對有些狀況進行捨棄)能夠得出最優解.

void BFSTraverse(Graph G, Status (* Visit) (int v)) {
    for (v= 0; v < G.vexnum; ++v) {
        visited[v] = FALSE;
    }
    InitQueue(Q);
    for (v = 0; v < G.vexnum; ++v) {
        if (!visited[v]) {
            visited[v] = TRUE;
            Visit(v);
            EnQueue(Q, v);
            while (!QueueEmpty(Q)) {
                DeQueue(Q, u);
                for (w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G, u, w)) {
                    // w 爲 u 還沒有訪問的鄰接頂點
                    if (!visited[w]) {
                        visited[w] = TRUE;
                        Visit(w);
                        EnQueue(Q, w);
                    } // if
                } // for
            } // while
        } // if
    } // for
} // BFSTraverse複製代碼

// 如下待填

7.3 圖的連通性問題
  • 無向圖的連通份量和生成樹
  • 有向圖的強連通份量
7.4 最小生成樹
  • Prim 算法 O(n2)

    沒圖戳 wikipedia 或 fitzeng.org
    沒圖戳 wikipedia 或 fitzeng.org

    以點爲主: 主要是分爲兩個集合, 一個是已加入的節點, 另外一個是未加入節點. 在未加入的節點集合中找到一個離已加入集合最近的節點加入. 直至全部節點被加入.

  • Kruskal 算法 O(eloge)

    沒圖戳 wikipedia 或 fitzeng.org
    沒圖戳 wikipedia 或 fitzeng.org

    以邊爲主: 初始條件是把圖的全部邊去除變成 V 個連通圖. 而後每次找一條代價最小的邊加入, 確保每加入一條邊連通圖個數都減小一個(也就是確保無環路)。直至成一個連通圖時就是最小生成樹.

7.5 最短路徑
  • Dijkstra 算法 O(n3)

    沒圖戳 wikipedia 或 fitzeng.org
    沒圖戳 wikipedia 或 fitzeng.org

    主要是維護一個表和一個已加入路徑集合, 表記錄從原點到每個點的當前最小權值. 若是已加入路徑集合中的點經過某條路徑對未加入集合中的點的最小權值有影響則更新該節點權值. 最後在每次更新完成後判斷目前未加入集合中的最小權值節點加入集合, 再對該節點的邊所達的節點作如上判斷. 最終能夠求出起點到每個點的全部最短路徑.

  • Floyd 算法 O(n3)

    主要是判斷通過該點到達的臨時目點的權值和該點目前權值(能夠不考慮是否已經通過, 可是循環只會掃一遍因此沒有什麼影響)的大小來判斷是否更新權值.

  • 關鍵路徑和拓撲排序 (KeyWord : 鬆弛)

相關文章
相關標籤/搜索