拓扑排序
其实只需要讲解清楚拓扑排序的原理就可以了.
每次将入度为 0 的数入队, 然后将它所指向的数的入度 -1.再重复将入度为 0 的数如队, 直到所有的数都入队结束
如图, 因为 1 的入度为 0 , 现将 1 入队, 接下来将入度为 0 的 2 入队, 再是 4 ,再是 3 , 最后 5 入度
整体的理解有了, 我们依旧使用链表将其每个数保存, 当然, 要快速的搜寻我们应该用到链表数组才行
链表Node保存的是一个数所指向的下一个数的角标, 而num_arr代表一个数的入度
struct Node;
struct Arr;
typedef struct Node *node;
typedef int Replace_Int;
const int N = 100;
/*
num_node : 保存所指向的数,即若 1 -> 2, 1 -> 3; 则num_node = 2; num_node = 3;
*/
struct Node
{
int num_node;
node next;
Node() : next(NULL) {}
};
/*
num_arr : 保存着该数的 入度 ; 即, 若 1 -> 2, 3 -> 2; 4 -> 2; 则 num_arr = 3;
arr_node : 指向链表 Node, 保存指向的数, 即, 若 2 -> 6, 2 -> 8, 2 -> 9; 则node链表保存 6, 8, 9;
*/
struct Arr
{
int num_arr;
node arr_node;
Arr() : arr_node(), num_arr(-1) {}
}arr[N];
插入, 将被指向的数的入度 +1, 然后指向的数的链表记录下被指向数的角标即可
//插入一组有向图, 即,若有向图为 1 -> 2, 输入(1, 2)
void Inset(Replace_Int a, Replace_Int b)
{
node T = new Node;
T->num_node = b;
//将被指向的 b 插入到 a 所指向的链表里;
T->next = arr[a].arr_node->next;
arr[a].arr_node->next = T;
//当 a 未被使用, 则将 a 的num_arr 初始化为0, 表示 a 被使用
if (arr[a].num_arr == -1)
arr[a].num_arr = 0;
//当 b 未被使用, 则将 b 的num_arr 初始化为0, 表示 b 被使用
if (arr[b].num_arr == -1)
arr[b].num_arr = 0;
//将 b 入度 ++;
arr[b].num_arr++;
}
将入度的为 0 的数入队, 然后搜寻它的链表所指向的角标, 将其指向的角标的数的入度都 -1.重复
//将有向图排序
void Sort()
{
//sort 队;
int sort[N] = { 0 };
//head, last 保存sort队 的位置
int head = 0, last = 0;
//将使用过的数且 入度为 0 的保存进入队; 并将其num_arr = -1;以免下次重复保存
for (int i = 0; i < N; i++)
if (arr[i].num_arr == 0)
{
sort[last++] = i;
arr[i].num_arr = -1;
}
//当没有入队的数时, head == last
while (head != last)
{
//将入队所指向的数的 入度减一
for (int i = head; i < last; i++)
{
//T : 入队的数将它所指向的链表保存
node T = arr[sort[i]].arr_node->next;
//将入队所指向的数的 入度减一
while (T != NULL)
{
arr[T->num_node].num_arr--;
T = T->next;
}
}
head = last;
//将使用过的数且 入度为 0 的保存进入队; 并将其num_arr = -1;以免下次重复保存
for (int i = 0; i < N; i++)
if (arr[i].num_arr == 0)
{
sort[last++] = i;
arr[i].num_arr = -1;
}
}
for (int i = 0; i < last; i++)
printf("%d ", sort[i]);
}
源代码
#include <stdlib.h>
#include <stdio.h>
struct Node;
struct Arr;
typedef struct Node *node;
typedef int Replace_Int;
const int N = 100;
/*
num_node : 保存所指向的数,即若 1 -> 2, 1 -> 3; 则num_node = 2; num_node = 3;
*/
struct Node
{
int num_node;
node next;
Node() : next(NULL) {}
};
/*
num_arr : 保存着该数的 入度 ; 即, 若 1 -> 2, 3 -> 2; 4 -> 2; 则 num_arr = 3;
arr_node : 指向链表 Node, 保存指向的数, 即, 若 2 -> 6, 2 -> 8, 2 -> 9; 则node链表保存 6, 8, 9;
*/
struct Arr
{
int num_arr;
node arr_node;
Arr() : arr_node(), num_arr(-1) {}
}arr[N];
//将整个数组初始化;
void Create(Arr arr[])
{
for (int i = 0; i < N; i++)
arr[i].arr_node = new Node;
}
//插入一组有向图, 即,若有向图为 1 -> 2, 输入(1, 2)
void Inset(Replace_Int a, Replace_Int b)
{
node T = new Node;
T->num_node = b;
//将被指向的 b 插入到 a 所指向的链表里;
T->next = arr[a].arr_node->next;
arr[a].arr_node->next = T;
//当 a 未被使用, 则将 a 的num_arr 初始化为0, 表示 a 被使用
if (arr[a].num_arr == -1)
arr[a].num_arr = 0;
//当 b 未被使用, 则将 b 的num_arr 初始化为0, 表示 b 被使用
if (arr[b].num_arr == -1)
arr[b].num_arr = 0;
//将 b 入度 ++;
arr[b].num_arr++;
}
//将有向图排序
void Sort()
{
//sort 队;
int sort[N] = { 0 };
//head, last 保存sort队 的位置
int head = 0, last = 0;
//将使用过的数且 入度为 0 的保存进入队; 并将其num_arr = -1;以免下次重复保存
for (int i = 0; i < N; i++)
if (arr[i].num_arr == 0)
{
sort[last++] = i;
arr[i].num_arr = -1;
}
//当没有入队的数时, head == last
while (head != last)
{
//将入队所指向的数的 入度减一
for (int i = head; i < last; i++)
{
//T : 入队的数将它所指向的链表保存
node T = arr[sort[i]].arr_node->next;
//将入队所指向的数的 入度减一
while (T != NULL)
{
arr[T->num_node].num_arr--;
T = T->next;
}
}
head = last;
//将使用过的数且 入度为 0 的保存进入队; 并将其num_arr = -1;以免下次重复保存
for (int i = 0; i < N; i++)
if (arr[i].num_arr == 0)
{
sort[last++] = i;
arr[i].num_arr = -1;
}
}
for (int i = 0; i < last; i++)
printf("%d ", sort[i]);
}
int main()
{
Create(arr);
Inset(1, 2);
Inset(1, 3);
Inset(2, 4);
Inset(3, 4);
Inset(3, 2);
Sort();
system("pause");
return 0;
}
下面的拓扑排序用来Hash的字符串计算, 因为有时候输入的是A, B, C 而不是 1 ,2 ,3 就不行, 所以在此添上了散列的一些元素
#include <stdlib.h>
#include <stdio.h>
struct Node;
struct Arr;
typedef struct Node *node;
typedef char* Replace_Char_Arr;
const int N = 1 << 10 + 1;
/*
num_node : 保存所指向的数,即若 1 -> 2, 1 -> 3; 则num_node = 2; num_node = 3;
*/
struct Node
{
int num_node;
node next;
Node() : next(NULL) {}
};
/*
num_arr : 保存着该数的 入度 ; 即, 若 1 -> 2, 3 -> 2; 4 -> 2; 则 num_arr = 3;
arr_node : 指向链表 Node, 保存指向的数, 即, 若 2 -> 6, 2 -> 8, 2 -> 9; 则node链表保存 6, 8, 9;
*/
struct Arr
{
Replace_Char_Arr ch;
int num_arr;
node arr_node;
Arr() : arr_node(), num_arr(-1){}
}arr[N];
//用散列来保存每个字符串的位置;
unsigned int Hash(Replace_Char_Arr key)
{
unsigned hash_size = 0;
while (*key != '\0')
hash_size = (hash_size << 5) + *key++;
return hash_size % N;
}
//将整个数组初始化;
void Create(Arr arr[])
{
for (int i = 0; i < N; i++)
arr[i].arr_node = new Node;
}
//插入一组有向图, 即,若有向图为 1 -> 2, 输入(1, 2)
void Inset(Replace_Char_Arr a, Replace_Char_Arr b)
{
unsigned int hash_size_a = Hash(a);
unsigned int hash_size_b = Hash(b);
node T = new Node;
T->num_node = hash_size_b;
//将被指向的 b 插入到 a 所指向的链表里;
T->next = arr[hash_size_a].arr_node->next;
arr[hash_size_a].arr_node->next = T;
//当 a 未被使用, 则将 a 的num_arr 初始化为0, 表示 a 被使用
if (arr[hash_size_a].num_arr == -1)
{
arr[hash_size_a].num_arr = 0;
arr[hash_size_a].ch = a;
}
//当 b 未被使用, 则将 b 的num_arr 初始化为0, 表示 b 被使用
if (arr[hash_size_b].num_arr == -1)
{
arr[hash_size_b].num_arr = 0;
arr[hash_size_b].ch = b;
}
//将 b 入度 ++;
arr[hash_size_b].num_arr++;
}
//将有向图排序
void Sort()
{
//sort 队;
int sort[N] = { 0 };
char *sort_char[N];
//head, last 保存sort队 的位置
int head = 0, last = 0;
//将使用过的数且 入度为 0 的保存进入队; 并将其num_arr = -1;以免下次重复保存
for (int i = 0; i < N; i++)
if (arr[i].num_arr == 0)
{
sort_char[last] = arr[i].ch;
sort[last++] = i;
arr[i].num_arr = -1;
}
//当没有入队的数时, head == last
while (head != last)
{
//将入队所指向的数的 入度减一
for (int i = head; i < last; i++)
{
//T : 入队的数将它所指向的链表保存
node T = arr[sort[i]].arr_node->next;
//将入队所指向的数的 入度减一
while (T != NULL)
{
arr[T->num_node].num_arr--;
T = T->next;
}
}
head = last;
//将使用过的数且 入度为 0 的保存进入队; 并将其num_arr = -1;以免下次重复保存
for (int i = 0; i < N; i++)
if (arr[i].num_arr == 0)
{
sort_char[last] = arr[i].ch;
sort[last++] = i;
arr[i].num_arr = -1;
}
}
for (int i = 0; i < last; i++)
printf("%s ", sort_char[i]);
/*
for (int i = 0; i < last; i++)
printf("%s ", arr[sort_char[i]].ch);
*/
}
int main()
{
Create(arr);
Inset("a", "b");
Inset("a", "c");
Inset("b", "c");
Inset("d", "b");
Inset("a", "e");
Sort();
system("pause");
return 0;
}