求有向无环图的所有拓扑序列

一 用到二个工具:

    1.回溯法的算法思想

    2.顺序表(主要用到了删除操作)

二 程序设计步骤:

    1.读入图;

       这里我没有用严格的图结构。而是用邻接矩阵来表示图,邻接矩阵放在一个txt文件中。(见后文)

       读入图就是指读入这个文件。

    2.计算图中顶点的入度;

       用一个结构体数组来存放顶点名称和顶点的入度(我这里的结构体名称是ElemType)

    3.初始化顺序表

       这一步只需初始化第0号顺序表。。。

       用2中的顶点入度数组来初始化。

    4.开始计算拓扑序列

       这里我们把图的每个顶点比作一个球,每个顺序表比作一个袋子。

       假设图有十个顶点,则需要十个袋子。(100个顶点,需要100个袋子。。。)

       这个问题与常见回溯算法不同的一个特点:从前一个袋子里取出球后,才能知道下一个袋子里装的是那几个球。

       思想如下:

       (1)将所有的球装入第0号袋子;

       (2)从袋子中取出一个球。如果合法(即入度为0),进行下一步;如果非法(即入度不为0),取下一个球。

       (3)根据(2)中取出的球,计算下一个袋子中的球的情况。上一步袋子中的球,除去取出的球外,全部放入下一个袋子(假设为A号袋子)中。根据取出的球(即顶点),

          计算A号袋子中球(即顶点)的入度。

       (4)重复步骤(2),每次袋子中都会少一颗球,直到最后一个袋子。取球的顺序即该图的一个拓扑排序;

       (5)从最后一个袋子开始回溯,直到回到第0号袋子,并把第0号袋子中的球取完为止。

    5.输出

三 示例

    1.需要拓扑排序的图

    2.存放邻接矩阵的文件。。

  

    3.代码

     (1)我的一个存放顺序表操作的头文件。。 

 1 #pragma once
 2 #ifdef ElemType
 3 #else
 4 #define ElemType int
 5 #endif
 6 #ifdef MaxSize
 7 #else
 8 #define MaxSize 10
 9 #endif
10 
11 //顺序表
12 struct sqList
13 {
14     ElemType data[MaxSize];
15     int length;
16 };
17 typedef struct sqList SqList;
18 
19 //初始化
20 void init(SqList* list)
21 {
22     list->length = 0;
23     return;
24 }
25 
26 //求长度
27 int getLength(SqList* list)
28 {
29     return list->length;
30 }
31 
32 //插入
33 int insert(SqList* list, int n, ElemType x)
34 {
35     if (list->length >= MaxSize || n < 0 || n > list->length)
36     {
37         return 0;
38     }
39     int i = list->length;
40     while (i > n)
41     {
42         list->data[i] = list->data[i - 1];
43         i--;
44     }
45     list->data[n] = x;
46     list->length++;
47     return 1;
48 }
49 
50 //删除
51 int del(SqList* list, int n, ElemType* x)
52 {
53     if (n < 0 || n > list->length - 1)
54     {
55         return 0;
56     }
57     int i = n;
58     *x = list->data[i];
59     while (i < list->length - 1)
60     {
61         list->data[i] = list->data[i + 1];
62         i++;
63     }
64     list->length--;
65     return 1;
66 }

     (2)开始求拓扑排序

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 struct elemType
  5 {
  6     int name;    //顶点名称
  7     int num;     //顶点的入度数
  8 };
  9 #define ElemType elemType
 10 #define MaxSize 10
 11 #define ROW 10
 12 #define COL 10
 13 #include"sq-list.h"
 14 
 15 SqList bags[COL + 1];     //袋子 
 16 
 17 int inputGraphic(const char *path, int mGraphic[][COL], int row);
 18 void getInDegree(int mGraphic[][COL], int row, ElemType degs[], int n);
 19 void initList(ElemType degs[], int n);
 20 int permulation(int mGraphic[][COL], int row, int n);
 21 void printResult(int result[], int n);
 22 
 23 
 24 int main()
 25 {
 26     const char* path = "F:\练习\c\graphic.txt";
 27     int mGraphic[ROW][COL];
 28     ElemType degs[COL];               //存放图中的顶点信息和入度数
 29     int counter = 0;
 30 
 31     if (!inputGraphic(path, mGraphic, ROW))
 32     {
 33         return 0;
 34     }
 35     getInDegree(mGraphic, ROW, degs, COL);
 36     initList(degs, COL);
 37     counter = permulation(mGraphic, ROW, COL);
 38     printf("这个图共有:%d种拓扑排序", counter);
 39     return 0;
 40 }
 41 
 42 //读入图
 43 int inputGraphic(const char* path, int mGraphic[][COL], int row)
 44 {
 45     int i, j;
 46     FILE* fp;
 47     fp = fopen(path, "r");
 48     if (fp == NULL)
 49     {
 50         return 0;
 51     }
 52     for (i = 0; i < ROW; i++)
 53     {
 54         for (j = 0; j < COL; j++)
 55         {
 56             fscanf(fp, "%d", &mGraphic[i][j]);
 57         }
 58     }
 59     fclose(fp);
 60     return 1;
 61 }
 62 
 63 //计算每个顶点的入度
 64 void getInDegree(int mGraphic[][COL], int row, ElemType degs[], int n)
 65 {
 66     int i, j;
 67     for (j = 0; j < COL; j++)
 68     {
 69         degs[j].name = j;
 70         degs[j].num = 0;
 71         for (i = 0; i < ROW; i++)
 72         {
 73             degs[j].num += mGraphic[i][j];
 74         }
 75     }
 76 }
 77 
 78 //初始化顺序表
 79 void initList(ElemType degs[], int n)
 80 {
 81     init(&bags[0]);
 82     int i = 0, j = 0;
 83     for (i = 0; i < n; i++)
 84     {
 85         bags[0].data[i] = degs[i];
 86     }
 87     bags[0].length = n;
 88 }
 89 
 90 //计算所有拓扑排序
 91 int permulation(int mGraphic[][COL], int row, int n)
 92 {
 93     int counter = 0;     //计数器,即共多少种排序方式
 94     int i = 0, j = 0;
 95     int temp = 0;
 96     ElemType ball, tempBall;
 97     int* index = (int*)malloc(sizeof(int) * n);
 98     int* result = (int*)malloc(sizeof(int) * n);
 99     if (index == NULL || result == NULL)
100     {
101         return -1;
102     }
103     for (i = 0; i < n; i++)
104     {
105         index[i] = 0;
106     }
107 
108     i = 0;
109     while (i >= 0)
110     {
111         //从第i号袋子中,取第index[i]号球
112         if (i < n)
113         {
114             if (index[i] >= bags[i].length)
115             {
116                 //回溯
117                 //当第i号袋子中所有的球都被取过之后,回溯到第i-1号袋子
118                 //同时要把i~n-1号袋子"还原",即index[i]=0,index[i+1]=0...
119                 //保证再次取到这个袋子时,依然时从0号球开始取
120                 temp = i;
121                 i--;
122                 while (temp < n)
123                 {
124                     index[temp++] = 0;
125                 }
126             }
127             else if (bags[i].data[index[i]].num != 0)
128             {
129                 //如果取出的球不合法(即度不为0),则继续取下一个球
130                 index[i] += 1;
131             }
132             else
133             {
134                 //取出一颗球
135                 result[i] = bags[i].data[index[i]].name;
136                 //生成下一个袋子里的球
137                 bags[i + 1] = bags[i];
138                 del(&bags[i + 1], index[i], &tempBall);
139                 for (j = 0; j < bags[i + 1].length; j++)
140                 {
141                     ball = bags[i + 1].data[j];
142                     if (mGraphic[tempBall.name][ball.name] == 1)
143                     {
144                         bags[i + 1].data[j].num--;
145                     }
146                 }
147                 //下次在从i号袋子里取球时,球index[i]+1号球
148                 index[i] += 1;
149                 //从下一个袋子里取球
150                 i++;
151             }
152         }
153         else
154         {
155             counter++;
156             printResult(result, n);
157             i--;
158         }
159     }
160     
161     return counter;
162     free(index);
163     free(result);
164 }
165 
166 void printResult(int result[], int n)
167 {
168     int i = 0;
169     for (i = 0; i < n; i++)
170     {
171         //此次加1是因为我的图中顶点是从1开始编号的,而程序中顶点从0开始编号
172         printf("%d,", result[i] + 1);    
173     }
174     printf("
");
175 }
原文地址:https://www.cnblogs.com/ben-/p/12531472.html