package main

import (
	"fmt"
)

// topoSort 函数返回一个切片，其中的字符串代表了可以安全学习的课程。
// m 参数表示每个课程的前置课程的映射。
//
//	func topoSort(m map[string][]string) []string {
//		// 定义一个 order 切片，用于存储排序后的课程名。
//		var order []string
//		// 定义一个 seen 映射，用于记录每个课程是否已经遍历过。
//		seen := make(map[string]bool)
//		// 定义一个 visitAll 函数，用于遍历所有的课程。
//		var visitAll func(items map[string]bool)
//		// 定义 visitAll 函数的实现体。
//		visitAll = func(items map[string]bool) {
//			// 遍历 items 参数中的所有课程。
//			for item := range items {
//				// 如果当前课程没有遍历过。
//				if !seen[item] {
//					// 将当前课程标记为已遍历。
//					seen[item] = true
//					// 递归调用 visitAll 函数，继续遍历当前课程的前置课程。
//					visitAll(m[item])
//					// 将当前课程追加到 order 切片的末尾。
//					order = append(order, item)
//				}
//			}
//		}
//		// 定义一个 keys 切片，用于存储 m 参数中所有课程的名称。
//		var keys = make(map[string]bool)
//		// 遍历 m 参数中的所有课程。
//		for key := range m {
//			// 将当前课程的名称追加到 keys 切片的末尾。
//			keys[key] = true
//		}
//		visitAll(keys)
//		// 返回 order 切片。
//		return order
//
// }

// topoSort 函数用于对给定的项目进行拓扑排序。
// 它接收一个字符串到字符串切片的映射 m，其中 m[i] 存储了项目 i 的依赖项目。
// 函数返回一个切片，表示拓扑排序后项目的顺序。
func topoSort(m map[string][]string) []string {
	// order 存储了项目的拓扑排序顺序。
	var order []string
	// seen 记录了已访问过的项目。
	seen := make(map[string]bool)
	// visitAll 函数递归访问 items 切片中的每个项目，并将它们按照正确的拓扑顺序添加到 order 切片中。
	var visitAll func(items []string)
	visitAll = func(items []string) {
		for _, item := range items {
			// 如果当前项目还没有被访问过，则递归调用 visitAll 函数，并将当前项目加入到 order 切片中。
			if !seen[item] {
				seen[item] = true
				visitAll(m[item])
				order = append(order, item)
			}
		}
	}
	// keys 存储了 m 中所有键的切片。
	var keys []string
	// 遍历 m 中的每个键，并将它们存储到 keys 切片中。
	for key := range m {
		keys = append(keys, key)
	}
	// 调用 visitAll 函数，并传入 keys 切片，从而从依赖图中的“叶子”节点（即没有依赖的项目）开始，
	// 逐步往上遍历依赖关系，并将项目添加到 order 切片中。
	visitAll(keys)
	// 返回 order 切片，表示拓扑排序后项目的顺序。
	return order
}

func main() {
	// prereqs 记录了每个课程的前置课程
	var prereqs = map[string][]string{
		"algorithms": {"data structures"},
		"calculus":   {"linear algebra"},
		"compilers": {
			"data structures",
			"formal languages",
			"computer organization",
		},
		"data structures":       {"discrete math"},
		"databases":             {"data structures"},
		"discrete math":         {"intro to programming"},
		"formal languages":      {"discrete math"},
		"networks":              {"operating systems"},
		"operating systems":     {"data structures", "computer organization"},
		"programming languages": {"data structures", "computer organization"},
	}
	// 调用 topoSort 函数，并将返回值存储到 courses 切片中。
	courses := topoSort(prereqs)
	// 遍历 courses 切片中的每个项目，并以“索引：项目”的格式将它们输出到屏幕上。
	// 这么做的目的是使map的输出是有序的
	for i := 0; i < len(courses); i++ {
		fmt.Printf("%d:\t%s\n", i+1, courses[i])
	}
}
