Skip to content

伪代码版本 · C

考场默写的书写习惯组织:省略 I/O 与错误处理细节,聚焦算法主干,变量命名与教材保持一致,便于直接誊写到答题卡。

文件一览

序号内容文件
01线性表01_线性表.c
02栈和队列02_栈和队列.c
03树与层序遍历03_树与层序遍历.c
04排序算法04_排序算法.c
05串与查找05_串与查找.c
06图的核心算法06_图的核心算法.c

01 线性表

c
#include <stdio.h>
#include <stdlib.h>

/* =========================================
 * 408 统考数据结构核心代码 - 线性表 (纯 C 语言风格)
 * 考试默写要求:极高。必须随手能写出链表的防断链操作。
 * ========================================= */

#define MaxSize 50
typedef int ElemType;

// 1. 顺序表结构体定义
typedef struct {
    ElemType data[MaxSize];
    int length;
} SqList;

// 2. 单链表结构体定义
typedef struct LNode {
    ElemType data;
    struct LNode *next;
} LNode, *LinkList;

/* -----------------------------------------
 * 【1】顺序表核心操作
 * ----------------------------------------- */

// 初始化顺序表
void InitList(SqList *L) {
    L->length = 0;
}

// 顺序表插入
// 注意:数组下标从 0 开始,第 i 个位置的下标为 i-1
int ListInsert(SqList *L, int i, ElemType e) {
    if (i < 1 || i > L->length + 1) return 0; // 判断 i 的范围是否有效
    if (L->length >= MaxSize) return 0;       // 存满了不能插
    
    for (int j = L->length; j >= i; j--) {
        L->data[j] = L->data[j - 1];          // 将第 i 个元素及之后的元素后移
    }
    L->data[i - 1] = e;                       // 在位置 i 放上 e
    L->length++;
    return 1;
}

// 顺序表删除
int ListDelete(SqList *L, int i, ElemType *e) {
    if (i < 1 || i > L->length) return 0;     // 判断 i 的范围是否有效
    *e = L->data[i - 1];                      // 【考点】取出被删除的元素
    for (int j = i; j < L->length; j++) {
        L->data[j - 1] = L->data[j];          // 将第 i 个位置之后的元素前移
    }
    L->length--;
    return 1;
}

/* -----------------------------------------
 * 【2】单链表核心操作
 * ----------------------------------------- */

// 头插法建立单链表(常用于链表的【原地逆置】)
LinkList List_HeadInsert(LinkList L) {
    LNode *s;
    int x;
    L = (LinkList)malloc(sizeof(LNode)); // 创建头结点
    L->next = NULL;
    
    scanf("%d", &x);
    while (x != 9999) { // 9999 为结束标志
        s = (LNode *)malloc(sizeof(LNode));
        s->data = x;
        
        // 核心两步,千万不能反!
        s->next = L->next; 
        L->next = s;
        
        scanf("%d", &x);
    }
    return L;
}

// 尾插法建立单链表(注意:必须增加一个尾指针 r)
LinkList List_TailInsert(LinkList L) {
    int x;
    L = (LinkList)malloc(sizeof(LNode));
    LNode *s, *r = L; // r 为表尾指针
    
    scanf("%d", &x);
    while (x != 9999) {
        s = (LNode *)malloc(sizeof(LNode));
        s->data = x;
        r->next = s;  // r 连上新结点
        r = s;        // r 指向新的表尾
        scanf("%d", &x);
    }
    r->next = NULL; // 【易错点】尾结点指针置空
    return L;
}

// 删除指定结点 p 的后继结点
// 考研大题常见子操作,注意判空保护
int DeleteNextNode(LNode *p) {
    if (p == NULL || p->next == NULL) return 0;
    
    LNode *q = p->next;  // 记录要删除的结点
    p->next = q->next;   // 断开联系
    free(q);             // 释放空间
    return 1;
}

// 找到链表的中间结点(经常利用双指针/快慢指针法)
LNode* FindMidNode(LinkList L) {
    LNode *p = L->next, *q = L->next;
    while (q != NULL && q->next != NULL) {
        p = p->next;       // 慢指针走一步
        q = q->next->next; // 快指针走两步
    }
    return p; // 当快指针到底时,慢指针正好在中间
}

02 栈和队列

c
#include <stdio.h>
#include <stdlib.h>

/* =========================================
 * 408 统考数据结构核心代码 - 栈与队列 (纯 C 语言风格)
 * 考试默写要求:高。循环队列的牺牲单元法判断满空必考。
 * ========================================= */

#define MaxSize 50
typedef int ElemType;

// 1. 顺序栈定义
typedef struct {
    ElemType data[MaxSize];
    int top; // 栈顶指针,初始为 -1
} SqStack;

// 2. 循环队列定义
typedef struct {
    ElemType data[MaxSize];
    int front, rear; // front 队头,rear 队尾
} SqQueue;


/* -----------------------------------------
 * 【1】顺序栈核心操作
 * ----------------------------------------- */

// 初始化
void InitStack(SqStack *S) {
    S->top = -1; // 初始化为 -1
}

// 判空
int StackEmpty(SqStack *S) {
    if (S->top == -1) return 1;
    else return 0;
}

// 进栈法
int Push(SqStack *S, ElemType x) {
    if (S->top == MaxSize - 1) return 0; // 栈满报错
    
    S->top = S->top + 1; // 先加指针
    S->data[S->top] = x; // 再入元素
    return 1;
}

// 出栈法
int Pop(SqStack *S, ElemType *x) {
    if (S->top == -1) return 0; // 栈空报错
    
    *x = S->data[S->top]; // 先取元素
    S->top = S->top - 1;  // 再减指针
    return 1;
}


/* -----------------------------------------
 * 【2】循环队列核心操作 (牺牲一个单元法)
 * ----------------------------------------- */

// 初始化队列
void InitQueue(SqQueue *Q) {
    Q->front = Q->rear = 0;
}

// 判空 (首尾相遇)
int QueueEmpty(SqQueue *Q) {
    if (Q->front == Q->rear) return 1;
    else return 0;
}

// 入队
int EnQueue(SqQueue *Q, ElemType x) {
    // 【考点】判断队满条件:尾指针的下一个位置是头指针时,就是满了
    if ((Q->rear + 1) % MaxSize == Q->front) return 0;
    
    Q->data[Q->rear] = x; // 放入队列
    Q->rear = (Q->rear + 1) % MaxSize; // 队尾指针加一取模
    return 1;
}

// 出队
int DeQueue(SqQueue *Q, ElemType *x) {
    if (Q->front == Q->rear) return 0; // 队空报错
    
    *x = Q->data[Q->front]; // 先取出当前队头元素
    Q->front = (Q->front + 1) % MaxSize; // 队头指针加一取模
    return 1;
}

03 树与层序遍历

c
#include <stdio.h>
#include <stdlib.h>

/* =========================================
 * 408 统考数据结构核心代码 - 树与遍历 (纯 C 语言风格)
 * 考试默写要求:超极高!前中后序的非递归大题神级利器!
 * ========================================= */

typedef int ElemType;

// 二叉树链式存储定义
typedef struct BiTNode {
    ElemType data;
    struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;

/* -----------------------------------------
 * 【1】必背神迹:各类递归遍历
 * ----------------------------------------- */

void visit(BiTNode *p) {
    printf("%d ", p->data);
}

// 先序遍历 (NLR)
void PreOrder(BiTree T) {
    if (T != NULL) {
        visit(T);               // 访问根结点
        PreOrder(T->lchild);    // 遍历左子树
        PreOrder(T->rchild);    // 遍历右子树
    }
}

// 中序遍历 (LNR)
void InOrder(BiTree T) {
    if (T != NULL) {
        InOrder(T->lchild);     
        visit(T);               
        InOrder(T->rchild);     
    }
}

// 后序遍历 (LRN)
void PostOrder(BiTree T) {
    if (T != NULL) {
        PostOrder(T->lchild);
        PostOrder(T->rchild);
        visit(T);
    }
}

/* -----------------------------------------
 * 【2】找双亲、找路径必备核心:DFS 加辅助栈的非递归 (中序演示)
 * 该方法属于 408 最常见的大题压轴解题利器!务必熟练。
 * ----------------------------------------- */

// 简化栈定义供演示
typedef struct {
    BiTNode* data[100];
    int top;
} BiStack;
// ... (此处省略 InitStack, Push, Pop 等基础实现)
int IsEmpty(BiStack *S) { return S->top == -1; }
void Push(BiStack *S, BiTNode* p) { S->data[++S->top] = p; }
void Pop(BiStack *S, BiTNode** p) { *p = S->data[S->top--]; }

// 非递归中序遍历
void InOrderNonRecursive(BiTree T) {
    BiStack S;
    S.top = -1;
    BiTree p = T;
    
    while (p != NULL || !IsEmpty(&S)) {
        if (p != NULL) {
            // 一头扎到最左边
            Push(&S, p);
            p = p->lchild;
        } else {
            // 左边走到头了,出栈访问,然后切入右边
            Pop(&S, &p);
            visit(p);
            p = p->rchild;
        }
    }
}

/* -----------------------------------------
 * 【3】层序遍历 (BFS) - 也是图的 BFS 与最短路的核心算法变种
 * ----------------------------------------- */
typedef struct {
    BiTNode* data[100];
    int front, rear;
} BiQueue;
// ... 假装实现了队列基本操作
void EnQueue(BiQueue* Q, BiTNode* p) { Q->data[Q->rear++] = p; }
BiTNode* DeQueue(BiQueue* Q) { return Q->data[Q->front++]; }
int QueueEmpty(BiQueue* Q) { return Q->front == Q->rear; }

void LevelOrder(BiTree T) {
    BiQueue Q;
    Q.front = Q.rear = 0;
    BiTree p;
    
    if(T != NULL) {
        EnQueue(&Q, T); // 根节点入队
    }
    
    while(!QueueEmpty(&Q)) {
        p = DeQueue(&Q);
        visit(p);
        
        if (p->lchild != NULL) {
            EnQueue(&Q, p->lchild);
        }
        if (p->rchild != NULL) {
            EnQueue(&Q, p->rchild);
        }
    }
}

/* -----------------------------------------
 * 【4】二叉树常见常考高级大题操作
 * ----------------------------------------- */

// 1. 求二叉树深度 (经典递归)
int TreeDepth(BiTree T) {
    if (T == NULL) return 0;
    
    int ldepth = TreeDepth(T->lchild);
    int rdepth = TreeDepth(T->rchild);
    
    // 树的高度 = 左右子树最大的加自己本身(1)
    return (ldepth > rdepth ? ldepth : rdepth) + 1;
}

// 2. 判别是否是平衡二叉树 (AVL 树)
// 利用后序遍历一边求深度一边判别,大幅度降级时间复杂度
int isBalanced(BiTree T, int *depth) {
    if (T == NULL) {
        *depth = 0;
        return 1; // 空树自然是平衡的
    }
    
    int ldepth, rdepth;
    // 分别检查左右孩子是否平衡
    if (isBalanced(T->lchild, &ldepth) && isBalanced(T->rchild, &rdepth)) {
        int diff = ldepth - rdepth;
        // 左右子树高低差不能超过 1
        if (diff >= -1 && diff <= 1) {
            *depth = (ldepth > rdepth ? ldepth : rdepth) + 1; // 更新给上一层
            return 1; 
        }
    }
    return 0; // 不平衡
}

/* -----------------------------------------
 * 【5】并查集 (Union-Find) 极高频考点
 * 一般用双亲表示法的结构数组来实现
 * ----------------------------------------- */

#define SIZE 100
int UFSets[SIZE]; // 并查集实质是个双亲指针数组

// 初始化并查集
void Initial(int S[]) {
    for (int i = 0; i < SIZE; i++) {
        S[i] = -1; // 初始时每个人都是自己的祖先,值为 -1
    }
}

// 并查集核心操作 1:Find 找祖宗
// (常考优化版本:路径压缩。直接顺带把沿途结点的爹全改成最大的祖宗)
int Find(int S[], int x) {
    int root = x;
    while (S[root] >= 0) { // 如果大于等于 0,说明有爹
        root = S[root];
    }
    // 路径压缩 (408重点:写出这步能极大的防丢分保满分)
    int curr = x, ptr;
    while (curr != root) {
        ptr = S[curr]; // 保存原来爹
        S[curr] = root; // 把直接爹改成祖宗
        curr = ptr;
    }
    return root; // 返回祖宗下标
}

// 并查集核心操作 2:Union 合并两个集合
// (传入的是祖宗节点,要求:小树合并入大树)
void Union(int S[], int Root1, int Root2) {
    if (Root1 == Root2) return; 
    
    // 我们约定 S[] 存的负数的绝对值为该集合拥有的结点总数
    if (S[Root2] < S[Root1]) { // Root2 人数更多 (负的更多)
        S[Root2] += S[Root1]; // 把人家吞并了人数加过来
        S[Root1] = Root2;     // Root1 的爹变成 Root2
    } else {
        S[Root1] += S[Root2];
        S[Root2] = Root1;
    }
}

04 排序算法

c
#include <stdio.h>
#include <stdlib.h>

/* =========================================
 * 408 统考数据结构核心代码 - 排序算法 (纯 C 语言风格)
 * 考试默写要求:快速排序的 Partition 函数每年极小选择和算法涉及极多!
 * ========================================= */

// 函数:交换两者
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

/* -----------------------------------------
 * 【1】快速排序及其核心 Partition 划分
 * ----------------------------------------- */

// 快速排序的划分思想(408常考:求第K大,奇偶分离等变形均由此出)
int Partition(int A[], int low, int high) {
    int pivot = A[low]; // 取第一个元素作为枢轴
    while (low < high) {
        // 从后往前找比枢轴小的
        while (low < high && A[high] >= pivot) high--; 
        A[low] = A[high]; // 扔到左边
        
        // 从前往后找比枢轴大的
        while (low < high && A[low] <= pivot) low++;
        A[high] = A[low]; // 扔到右边
    }
    A[low] = pivot; // 枢轴到达最终的位置!
    return low;
}

// 快排主骨架
void QuickSort(int A[], int low, int high) {
    if (low < high) {
        int pivotpos = Partition(A, low, high); // 划分
        QuickSort(A, low, pivotpos - 1);        // 治理左边
        QuickSort(A, pivotpos + 1, high);       // 治理右边
    }
}


/* -----------------------------------------
 * 【2】起泡排序 (冒泡) / 稳定的基础大哥
 * ----------------------------------------- */
void BubbleSort(int A[], int n) {
    int flag; // 标志位用于判断某趟有没有发生交换
    for (int i = 0; i < n - 1; i++) {
        flag = 0; // 假设没交换
        for (int j = n - 1; j > i; j--) { // 从后往前冒泡
            if (A[j - 1] > A[j]) {
                swap(&A[j - 1], &A[j]);
                flag = 1;
            }
        }
        if (flag == 0) return; // 本趟全都没交换,说明已经彻底有序了!打卡下班。
    }
}


/* -----------------------------------------
 * 【3】折半插入排序 
 * ----------------------------------------- */
void InsertSortBinary(int A[], int n) {
    int i, j, low, high, mid;
    // 数组下标从1到n有效的话(A[0]作为哨兵或者辅助位保存数据)
    for (i = 2; i <= n; i++) {
        A[0] = A[i]; // 将 A[i] 暂存
        low = 1; 
        high = i - 1; 
        
        // 折半查找应该插入的位置
        while (low <= high) {
            mid = (low + high) / 2;
            if (A[mid] > A[0]) {
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
        // 统一后移,空出位置
        for (j = i - 1; j >= high + 1; j--) {
            A[j + 1] = A[j];
        }
        A[high + 1] = A[0]; // 填入
    }
}

/* -----------------------------------------
 * 【4】归并排序 (Merge Sort) 
 * 【极度重要】需要单独开辟辅助数组 B,这是耗费空间 O(n) 的来源
 * ----------------------------------------- */
int B[100]; // 辅助数组

// 归并两个有序小段的核心机制
void Merge(int A[], int low, int mid, int high) {
    int i, j, k;
    for (k = low; k <= high; ++k) {
        B[k] = A[k]; // 临时复制到背板去
    }
    
    // i走前段表,j走后段表,看两边较小的值依次填入 A 中归并
    for (i = low, j = mid + 1, k = i; i <= mid && j <= high; ++k) {
        if (B[i] <= B[j]) {
            A[k] = B[i++]; 
        } else {
            A[k] = B[j++];
        }
    }
    
    // 如果某一段多出来了,将剩下的所有统统灌入末尾结账
    while (i <= mid)  A[k++] = B[i++];
    while (j <= high) A[k++] = B[j++];
}

// 归并排序递归骨架
void MergeSort(int A[], int low, int high) {
    if (low < high) {
        int mid = (low + high) / 2;
        MergeSort(A, low, mid);       // 排理前一半
        MergeSort(A, mid + 1, high);  // 排理后一半
        Merge(A, low, mid, high);     // 天下合并
    }
}

/* -----------------------------------------
 * 【5】408 快排核心变式应用集锦 
 * 这往往出现在 11 到 15 分的大题中,让你 O(n) 完成特殊分离!
 * ----------------------------------------- */

// 王道经典考题:把所有的奇数移向数组前端,全部偶数移向末尾,要求时间 O(N) 一趟!
// 【破局原理】直接调用 Partition 思想。
void MoveOddEven(int A[], int len) {
    int low = 0, high = len - 1;
    while(low < high) {
        // 后方找到第一个奇数
        while(low < high && A[high] % 2 == 0) high--;
        // 前方找到第一个偶数
        while(low < high && A[low] % 2 != 0) low++;
        
        if (low < high) {
            swap(&A[low], &A[high]); // 被抓到两人不符合规矩,交换换身!
        }
    }
}

05 串与查找

c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* =========================================
 * 408 统考数据结构核心代码 - 串与查找 (C 版本)
 * KMP 算法的 next 数组推导属于选择与大题的高频常青树!
 * ========================================= */

/* -----------------------------------------
 * 【1】字符串匹配:KMP 算法核心
 * 特别注意:王道考研中,字符串通常从下标 1 开始存储,
 * S.ch[0] 用来存放真实的长度。
 * ----------------------------------------- */

typedef struct {
    char ch[100]; // 静态分配
    int length;
} SString;

// 1. 推导 next 数组的灵魂逻辑 (必背)
void get_next(SString T, int next[]) {
    int i = 1, j = 0;
    next[1] = 0;
    
    // 如果还没推到头
    while (i < T.length) {
        if (j == 0 || T.ch[i] == T.ch[j]) {
            ++i; ++j;
            next[i] = j; // 匹配上了就将匹配长度同步递增赋予给下一位
        } else {
            j = next[j]; // 没匹配上,j 回退到次级的容错庇护所
        }
    }
}

// 2. KMP 主干匹配计算
int Index_KMP(SString S, SString T, int next[]) {
    int i = 1, j = 1; // 设从 1 开始
    
    while (i <= S.length && j <= T.length) {
        if(j == 0 || S.ch[i] == T.ch[j]) {
            ++i; ++j; // 匹配就接着往下走
        } else {
            j = next[j]; // 失配借用 next 发生神级跳跃回溯!
        }
    }
    
    if (j > T.length) {
        return i - T.length; // 找到了
    } else {
        return 0; // 没找到
    }
}


/* -----------------------------------------
 * 【2】折半查找 (Binary Search)
 * 要求必须建立在有序并且拥有随机访问能力(数组)的基础上!
 * ----------------------------------------- */

// 非递归折半查找 (最常用)
int Binary_Search(int A[], int len, int key) {
    int low = 0;
    int high = len - 1;
    int mid;
    
    while (low <= high) {
        mid = (low + high) / 2;
        
        if (A[mid] == key) {
            return mid;  // 匹配成功,返回位置下标
        } else if (A[mid] > key) {
            high = mid - 1; // 查左半边
        } else {
            low = mid + 1;  // 查右半边
        }
    }
    
    return -1; // 查找失败
}

// 递归版本的折半查找 (大题中有可能会用于分治变形)
int Binary_Search_Rec(int A[], int low, int high, int key) {
    if (low > high) return -1;
    
    int mid = (low + high) / 2;
    if (A[mid] == key) return mid;
    if (A[mid] > key) {
        return Binary_Search_Rec(A, low, mid - 1, key);
    } else {
        return Binary_Search_Rec(A, mid + 1, high, key);
    }
}

06 图的核心算法

c
#include <stdio.h>
#include <stdlib.h>

/* =========================================
 * 408 统考数据结构核心代码 - 图的核心算法 (C 版本)
 * 考研热点:基于邻接表的极简 BFS/DFS 搜索!
 * ========================================= */

#define MaxVertexNum 100

// 边/弧结点
typedef struct ArcNode {
    int adjvex;               // 指向那个顶点
    struct ArcNode *nextarc;  // 指向下一条弧
    // int info;              // 如果有网,这里可以带权值
} ArcNode;

// 顶点结构体
typedef struct VNode {
    int data;                 // 顶点信息
    ArcNode *firstarc;        // 指向第一个依附该顶点的弧
} VNode, AdjList[MaxVertexNum];

//图的邻接表体系
typedef struct {
    AdjList vertices;         // 存放全部顶点的表头
    int vexnum, arcnum;       // 目前的顶点数和弧数
} ALGraph;

/* -----------------------------------------
 * 【1】BFS 与 DFS 的基本框架 (常考大题防丢分模板)
 * ----------------------------------------- */
int visited[MaxVertexNum];

// 访问函数
void visit(int v) {
    printf("访问到了节点 %d\n", v);
}

// ------ 深度优先 DFS ------
void DFS(ALGraph *G, int v) {
    visit(v);              // 1. 访问它
    visited[v] = 1;        // 2. 打点标记
    
    ArcNode *p = G->vertices[v].firstarc; // 拿邻居
    while (p != NULL) {
        int w = p->adjvex;
        if (!visited[w]) { // 如果该邻居没去过
            DFS(G, w);     // 递归往里扎
        }
        p = p->nextarc;    // 退出来后找下一个兄弟遍历
    }
}

// 处理非连通图的全盘唤醒调度器
void DFSTraverse(ALGraph *G) {
    for (int i = 0; i < G->vexnum; i++) visited[i] = 0; // 清场
    
    for (int i = 0; i < G->vexnum; i++) {
        if (!visited[i]) {
            DFS(G, i);
        }
    }
}

// ------ 广度优先 BFS (借助外部队列) ------
// 伪代码展示队列行为,由于是 C 所以手撸一根简易队伍
int queue[100];
int front = 0, rear = 0;
void EnQueue(int x) { queue[rear++] = x; }
int DeQueue() { return queue[front++]; }
int QueueEmpty() { return front == rear; }

void BFS(ALGraph *G, int v) {
    visit(v);
    visited[v] = 1;
    EnQueue(v); // 入队
    
    while (!QueueEmpty()) {
        int target = DeQueue();
        ArcNode *p = G->vertices[target].firstarc;
        
        while (p != NULL) {
            int w = p->adjvex;
            if (!visited[w]) { // 如果没走过
                visit(w);      // 访问
                visited[w] = 1;// 标记
                EnQueue(w);    // 扔进队伍做后续扩展
            }
            p = p->nextarc;
        }
    }
}

void BFSTraverse(ALGraph *G) {
    for (int i = 0; i < G->vexnum; i++) visited[i] = 0; 
    front = rear = 0; // 重置队伍
    
    for (int i = 0; i < G->vexnum; i++) {
        if (!visited[i]) BFS(G, i);
    }
}

/* -----------------------------------------
 * 【2】Dijkstra 最短路径 (伪代码框架)
 * 考研大题常见变式:在邻接矩阵图上寻求源点到各点最低票价
 * ----------------------------------------- */
#define INF 999999
int dist[MaxVertexNum];
int path[MaxVertexNum];
int final[MaxVertexNum];

// G.Edge 即为邻接矩阵的距阵二阶表
void Dijkstra(int curr_vex, int vexnum, int Edge[][MaxVertexNum]) {
    // 1. 初始化
    for (int i = 0; i < vexnum; i++) {
        dist[i] = Edge[curr_vex][i];
        final[i] = 0;     // 初始全在 P-S 集合
        if (dist[i] < INF) {
            path[i] = curr_vex;
        } else {
            path[i] = -1;
        }
    }
    
    final[curr_vex] = 1; 
    dist[curr_vex] = 0;
    
    // 2. 将剩下的所有点归位
    for (int i = 0; i < vexnum - 1; i++) {
        int min = INF;
        int min_id = -1;
        
        // (1)找 S 外缘跟 S 结合最紧密的那个小弟
        for (int j = 0; j < vexnum; j++) {
            if (final[j] == 0 && dist[j] < min) {
                min = dist[j];
                min_id = j;
            }
        }
        
        if(min_id == -1) break; // 已经找无可找了
        
        final[min_id] = 1; // 开光加入神坛集合 S
        
        // (2)借助由于此小弟加入导致的新路,将原来其他非神坛的人距离拉踩刷新
        for (int j = 0; j < vexnum; j++) {
            if (final[j] == 0 && dist[min_id] + Edge[min_id][j] < dist[j]) {
                dist[j] = dist[min_id] + Edge[min_id][j];
                path[j] = min_id; // 修改他通往神坛的接入点
            }
        }
    }
}

Released under the MIT License.