拓扑排序
原理:参考趣学数据结构
代码:
栈代码放入stack.h中作为自定义库使用
#pragma once
#include<stdio.h>
#define maxSize 100
typedef struct stack {
int * base;
int * top;
}stack;
bool init(stack & Stack) {//栈的初始化
Stack.base = new int[maxSize];
if (!Stack.base) {
return false;
}
Stack.top = Stack.base;
return true;
}
bool push(stack & Stack,int e) {//入栈
if (Stack.top - Stack.base == maxSize) {//满栈,不能再插入
return false;
}
*(Stack.top) = e;
Stack.top++;
return true;
}
bool pop(stack & Stack, int &e) {//出栈
if (Stack.base == Stack.base) {//栈空
return false;
}
Stack.top--;
e = *(Stack.top);
return true;
}
int getTop(stack Stack) {
if (Stack.base == Stack.top) {//栈空
return -1;
}
return *(Stack.top - 1);
}
void printStack(stack Stack) {//遍历栈中的元素
while (Stack.base != Stack.top) {
printf("%d ", *(Stack.top - 1));
Stack.top--;
}
}
bool empty(stack Stack) {//栈空的判断
if (Stack.base == Stack.top) {
return true;
}
return false;
}
void testStack() {//测试栈是否有问题
stack Stack;
init(Stack);
int value;
while (1) {
scanf_s("%d", &value);
if (value == -1) {
break;
}
push(Stack, value);
}
printStack(Stack);
}
拓扑排序代码:
#include<stdio.h>
#include<stdlib.h>
#include "stack.h"
#define typeNode int //每个头结点的标识数据类型
#define N 100 //最大结点数
int degree[N];
int result[N];
int count = 0;//计数
typedef struct dNode {//每个头结点后紧跟的单位结点
int data;
struct dNode * next;
}dNode;
typedef struct mNode {//邻接表中每一行的头结点
typeNode data;
dNode * first;//指向第一个有效的后继结点
}mNode;
typedef struct {
mNode vNode[N];//所有头结点
int vNum, eNum;//图中顶点的数量和边数量
}zNode;
void init(zNode &ZNode) {
printf("规定顶点从0开始取\n");
scanf_s("%d%d", &ZNode.vNum, &ZNode.eNum);//输入有向图的顶点数和边数
for (int i = 0; i < ZNode.vNum; i++) {//规定顶点从0开始取
scanf_s("%d", &ZNode.vNode[i].data);
ZNode.vNode[i].first = NULL;
}
for (int i = 0; i < ZNode.eNum; i++) {
int u, v;
scanf_s("%d%d", &u, &v);//u顶点到v顶点有边
dNode* p = new dNode();
p->data = v;
p->next = ZNode.vNode[u].first;//只有指针域,指向地址
ZNode.vNode[u].first= p;
}
}
void print(zNode ZNode) {
printf("遍历链表:\n");
for (int i = 0; i < ZNode.vNum; i++) {
dNode* temp = ZNode.vNode[i].first;
printf("%d ->", ZNode.vNode[i].data);
while(temp){
printf("%d ->",temp->data);
temp = temp->next;
}
printf("NULL\n");
}
}
void calculate(zNode ZNodeReverse) {//返回有向图每个顶点的入度
//每个顶点的入度
for (int i = 0; i < ZNodeReverse.vNum; i++) {
int tempLength = 0;
dNode* p = new dNode();
p = ZNodeReverse.vNode[i].first;
while (p) {
tempLength ++;
p = p->next;
}
degree[i] = tempLength;
}
}
bool tuoPuSort(zNode ZNode,stack &Stack) {//拓扑排序只是找到学习的先后依赖顺序,并不是排序
for (int i = 0; i < ZNode.vNum; i++) {
if (!degree[i]) {//对入度为0的点入栈
push(Stack, i);
}
}
while (!empty(Stack)) {
dNode* p ;
int tempV = getTop(Stack);
result[count] = tempV;
count++;
int e;
pop(Stack, e);
p = ZNode.vNode[tempV].first;//取以tempV顶点为入度点
while (p) {//和tempV相连的邻接边的入度减1
int v = p->data;
degree[v]--;
if (!degree[v]) {
push(Stack, v);
}
p = p->next;
}
}
if (count < ZNode.vNum) {
return false;
}
else {
return true;
}
}
int main() {
zNode ZNode,ZNodeReverse;
printf("邻接表的构造:\n");
init(ZNode);
print(ZNode);
printf("逆邻接表的构造:\n");
init(ZNodeReverse);
print(ZNodeReverse);
calculate(ZNodeReverse);
stack Stack;
init(Stack);
printf("拓扑序列如下: ");
if (tuoPuSort(ZNode, Stack)) {
for (int i = 0; i < ZNode.vNum; i++) {
printf("%d ", result[i]);
}
}
printf("\n");
system("pause");
return 0;
}
测试:
应用场景:
应用在比如学习每门课程这种有先学哪门课程,后学哪门课程的拓扑序列挑选中。
可能还会存在的问题:内存、地址、指针、数组越界、初始化