一 用到二個工具:
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 }