巧用 指针/引用 替代递归处理父级、子级ID层级问题

常见的业务场景: 无限级分类菜单、无限员工丛属关系等
难度系数: 初级

这里以golang为演示,支持引用传递或者指针数据类型的编程语言都可实现

题目

ManagerID为父级ID,对应ID字段,Subordinateschildren子集,将下面数据处理成具有层级关系的结构

type Employee struct {
	ID           int
	Name         string
	Salary       float64
	ManagerID    int
	Subordinates []*Employee
}
csvData := []*Employee{
	{ID: 1, Name: "Alice", Salary: 100000, ManagerID: 0},
	{ID: 2, Name: "Bob", Salary: 75000, ManagerID: 1},
	{ID: 5, Name: "Dan", Salary: 50000, ManagerID: 2},
	{ID: 10, Name: "Ian", Salary: 30000, ManagerID: 5},
	{ID: 11, Name: "Jane", Salary: 30000, ManagerID: 5},
	{ID: 6, Name: "Ed", Salary: 50000, ManagerID: 2},
	{ID: 12, Name: "Kyle", Salary: 50000, ManagerID: 6},
}

答案

// 原始数据填充到map类型中,查询时间复杂度O1
// 注意:这里的map的v是指针类型,与原始数据的地址是一致的
employeeMap := make(map[int]*Employee)
for _, emp := range csvData {
	employeeMap[emp.ID] = emp
	emp.Subordinates = []*Employee{} // 初始化Subordinates
}

for _, emp := range csvData {
	if emp.ManagerID != 0 { // 排除顶级员工(ManagerID为0)
		if manager, ok := employeeMap[emp.ManagerID]; ok {
			manager.Subordinates = append(manager.Subordinates, emp)
		}
	}
}

var topLevelEmployees []*Employee
for _, emp := range csvData {
	if emp.ManagerID == 0 {
		topLevelEmployees = append(topLevelEmployees, emp)
	}
}

// 两个内存地址是一样
fmt.Println("Memory address of ePtr:", fmt.Sprintf("%p", csvData[0]))
fmt.Println("Memory address of ePtr:", fmt.Sprintf("%p", employeeMap[1]))

// 利用 json 来验证处理的数据格式
marshal, _ := json.Marshal(topLevelEmployees)
fmt.Println(string(marshal))

总结: 巧妙的利用了编程语言的引用类型,与map查询时间复杂度,并且在操作子集的数据填充时,有些链表的影子,for循环中每个元素只需要关系自己的下一级,无需关注自己的下下级

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值