第三个一千行+500行总结-数据结构C复习--知识点总结3--七到九章

本文主要回顾了C语言实现的数据结构中的图遍历(深度优先搜索DFS和广度优先搜索BFS)、图的应用如求简单路径、最小生成树(Prim和Kruskal算法)以及拓扑排序。此外,还涵盖了查找算法(包括邻接矩阵和邻接表的实现)和各种排序算法,如冒泡排序、快速排序、选择排序和堆排序的细节和原理。文章通过代码实例详细阐述了这些算法的实现过程。
摘要由CSDN通过智能技术生成

第七章 (接知识点总结2) 图

图的遍历:

//深度优先搜索
#define OK 1
#define True  1
#define Error -1
#define False 0
typedef enum{DG, DN, UDG. UDN}Graph;

int visited[MAX];
//Graph代表图的一种存储结构比如邻接表,邻接矩阵 
void TranverseGraph(Graph g){
    int vi;
    
    for(vi = 0; vi < g.vernum; vi++) 
        visited[vi] = False;
    for(vi = 0; vi < g.vernum; vi++){//连通图那么此操作执行一次 
        if(!visited[vi])
            DepthFirstSearch(g, vi);    
    }

void DepthFirstSearch(Graph g, int v0)
{
    visit(v0);
    visited[v0] = True;
    
    w = FirstAdjVertex(g, v0);
    while(w != -1){
        if(visited[w])
            DepthFirstSearch(g, w);
        w = NextAdjVertex(g, v0, w);
    }

深度遍历总结:总之就是一直找邻接点,找到一个那么找这个结点的下一个邻接点,找不到就换...

对于邻接表:
void DepthFirstSearch(AdjList g, int v0){
    visit(v0);
    visited[v0] = True;//这里的True是宏定义,bool类型的为true
    
    ArcNode *p;
    p =  g.vertex[v0].firstarc;
    while(p){
        if(!visited[p->adjvex])
            DepthFirstSearch(g, p->adjvex);
        p = p->nextarc;
    }

图的遍历--广度优先搜索 
void BreadFirstSearch(Graph g int v0){
    visit(v0);
    visited[v0] = True;//标志数组,证明该结点已经访问过 
    
    InitQueue(&Q);
    EnterQueue(&Q, v0);
    
    while(!IsEmpty(Q)){
        DeleteQueue(&Q, &v);
        w = FirstAdjVertex(g, v);
        while(w != -1){
            if(!visited[w]){
                visit(w);
                visited[w] = True;
                EnterQueue(&Q, w);
            }
            w = NextAdjVertex(g, v, w);
        }
    }

广度遍历总结:就是一层一层的访问,访问完这一个结点衍生出去路径为1的结点,在走下一层...


图的应用

//求图中两个节点的简单路径
int pre[];

void one_path(Graph *G, int u, int v)
{
    //找到一条从u到v结点的简单路径
    int i;
    pre = (int *)malloc(G->vexnum * sizeof(int));
    for(i = 0; i < G->vernum; i++)
        pre[i] = -1;//未访问标志 
    pre[u] = -2;//访问了,无前驱 
    DSF_path(G, u, v);
    free(pre); 
}

int DSF_path(Graph *G, int u, int v){
    int j;
    for(j = FirstAdj(G, u); j >= 0; j = nextadj(G, u, j)){
        if(pre[j] == -1){
            pre[j] = u;
            if(j == v)
            {
                print_path(pre, v);
                return 1;
            }
            else if(DFS_path(G, j, v))
                return 1; 
        }    
    }
    return 0;

生成树:一个连通图的生成树是一个极小联通子图, 含有全部顶点,只有构成一棵树的n-1条边
最小生成树:各边代价之和最小的生成树

Prime算法:
思想:点集分为两个U,V-U, 分别(U)存树上的结点和(V-U)去掉U中结点的剩余结点;从V-U种选择代价最小的边
    并入边集,直到U=V.这一算法不会构成回路, 因为并入的边始终是邻接点分布在U和V-U中.
     
//邻接矩阵
#define MAXV ...
typedef struct{
    int no;//顶点编号 
    InfoType info;
}VertexType;
typedef struct{
    int edges[MAXV][MAXV];//邻接矩阵 
    int n, e;//顶点数量, 边数 
    VertexType vexs[MAXV];//存放结点信息 
}MatGraph; 
#define M 32767
void Prime(MatGraph g, int v){
    int lowcost[MAXV];
    int min;
    int closet[MAXV];
    int i, j ,k;
    for(i = 0; i < g.n; i++){
        lowcost[i] = g.edges[v][i];
        closet[i] = v;
    }
    for(i = 1; i < g.n; i++){
        min = M;
        for(j = 0; j < g.n; j++){
            if(lowcost[j] != 0 && lowcost[j] < min){
                min = lowcost[j];
                k = j;
            }
        }
        printf("边(%d, %d)权为: %d", v, k, lowcost[k]);
        lowcost[k] = 0;
        
        for(j = 0; j < g.n; j++){
            if(lowcost[j] != 0 && lowcost[j] > g.edges[k][j])
            {
                lowcost[j] = g.edges[k][j];
                closet[j] = k;
            }
        }
    }
}


Kruskal 
总结:对所有边的权重值按照升序排列,依次选取权重较小的边,
     确保不构成回路(选中的边的所有结点不能重复出现在新加入的一条边中)     
     
#define 32367
typedef struct{
    int u;
    int v;
    int w;
    //边的始点, 重点, 权重 
}Edge;

void Kruskal(MatGraph h){
    
    int i, j, u1, v1, sn1, sn2, k;
    int vset[MAXV];
    Edge E[MaxSize];
    
    k = 0;//指示数组E的下标
    
    //对于边(权重)初始化 
    for(i = 0; i < g.n; i++){
        for(j = i + 1; j < g.n; j++)//上三角 
            if(g.edge[i][j] != M)//M = 32367
            {
                E[k].u = i; E[k].v = j;
                E[k].w = g.edge[i][j]; k++;
            }
    }
    //冒泡排序最简单 
    Sort(E, edge); //升序, 权值递增 
    
    for(i = 0; i < g.n; i++)//初始化辅助数组 
        vset[i] = i;
        
    k = 1;//k:当前构造生成树的第几条边, 初始值为1
    j = 0;//E中边的下标
    while(k < g.n){
        
        u1 = E[j].u;
        v1 = E[j].v;
        sn1 = vset[u1];
        sn2 = vset[u2];
        
        if(sn1 != sn2){
            printf("(%d, %d): %d", u1, v1, E[j].w);
            k++;
            for(i = 0; i < g.n; i++){
                if(vset[i] == sn2)
                    vset[i] = sn1;//改结点相同, 表示这两个结点已经形
                    //通路, 避免成环 
            }
            j++; 
        } 
    } 
}

拓扑排序

原理: 对于邻接矩阵
找入度为零的结点i, 即列为零的结点,标记, 将其删除, 删除邻接边即将序号i的行置零 , 重复...

邻接表
加一个辅助数组记录每个结点的入度; 入度为0, 入栈; 
栈非空, 出栈, 删除邻接边;
即辅助数组邻接点的总数count-1; 

//邻接表定义如下
typedef struct ANode{
    int adjvex; // 该边的终点编号 
    struct Anode *nextarc;
}ArcNode; 
typedef struct{
    Vertex data;
    int count;//辅助数组, 存放入度 
    ArcNode *firstarc;
}VNode;
typedef struct{
    VNode adjlist[MAV];
    int n, e;
}AdjGraph;

拓扑排序
//基于邻接表 
void TopSort(AdjGraph *G){
     int i, j;
     int st[MAXV],  top = -1;//栈的指针
    ArcNode *p;
    
    for(i = 0; i < G->n;i++){//入度置初值为0 
        G->adjlist[i].count = 0;
    } 
    for(i = 0; i < G->n; i++){//求所有顶点的入度 
        p = G->adjlist[i].firstarc;
        while(p!=NULL){
            G->adjlist[p->adjvex].count++;
            p = p->nextarc;//邻接表 
        }
    }
    for(i = 0; i < G.n; i++){//入度为零进栈 
        if(G->adjlist[i].count == 0){
            top++;
            st[top] = i;
        }
    }
    
    while(top != -2){
        
        i = st[top]; top--;//出栈一个顶点i 
        printf("%d", i);
        
        p = G->adjlist[i].firstarc;
        while(p != NULL){
            j = p->adjvex;//找出p的邻接点,入度-1 
            G->adjlist[j].count--;
            if(G->adjlist[j].count == 0){//入度为0入栈 
                top++;
                st[top] = j;
            }
            p = p->nextarc;
        }
        
    }
 }
 
AOE网--边表示活动的网
唯一入度为0的顶点为源点,唯一出度为0的顶点为汇点
源点到汇点的最长路径长度为整个工程任务所需时间,称为关键路径
关键路径上的活动称为关键活动.


//迪杰斯特算法 看PPT,难度较大 
void Dijkstra(MatGraph g, int v){ // v is the original dot.
    int dist[MAXV], path[MAXV];   //dist is to memorize the weighted length of the path.
    //path is used to memorize the node of the path
    int s[MAXV]; //to mark the node whether have been used.
    int mindist, i, j;
    
    for(i = 0; i < g.n; i++){
        dist[i] = g.edges[v][i]; //Firstly store the weighted length of the related edge.
        //If it is not relevant to it, put infinite on it. If it is itself, put 0 on it
        s[i] = 0;//s[] is cleared.
        if(g.edge[v][i] < INF)//如果v和i邻接那么赋值i的邻接点为v 
            path[i] = v;
        else
            path[i] = -1;//path is used to memorize the node before the latest
        //if it is -1, proven there is no path.
    s[v] =1; 
    for(i = 0; i < g.n; i++){//找出路径长度最小顶点u 
        mindis = INF;
        for(j = 0; j < g.n; j++)//Find out the shortest length of the node.
            if(s[j] == 0 && dist[j] < mindis){
                u = j;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风起风里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值