求有向無環圖的所有拓撲序列


一 用到二個工具:

    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("\n");
175 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM