unionfind.zig 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. const std = @import("std");
  2. const coordModule = @import("coord.zig");
  3. const areaModule = @import("area.zig");
  4. const Coord = coordModule.Coord;
  5. const Area = areaModule.Area;
  6. pub const UnionFindNode = struct {
  7. parent: usize,
  8. size: usize,
  9. };
  10. pub const UnionFind = struct {
  11. nodes: []UnionFindNode,
  12. nodesAllocator: std.mem.Allocator,
  13. pub fn Find(self: *UnionFind, nodeIndex: usize) usize {
  14. if (self.nodes[nodeIndex].parent == nodeIndex) {
  15. return nodeIndex;
  16. }
  17. self.nodes[nodeIndex].parent = self.Find(self.nodes[nodeIndex].parent);
  18. return self.nodes[nodeIndex].parent;
  19. }
  20. fn Union(self: *UnionFind, nodeAIndex: usize, nodeBIndex: usize) bool {
  21. var nodeARootIndex = self.Find(nodeAIndex);
  22. var nodeBRootIndex = self.Find(nodeBIndex);
  23. if (nodeARootIndex == nodeBRootIndex) {
  24. return false;
  25. }
  26. if (self.nodes[nodeARootIndex].size < self.nodes[nodeBRootIndex].size) {
  27. const t = nodeBRootIndex;
  28. nodeBRootIndex = nodeARootIndex;
  29. nodeARootIndex = t;
  30. }
  31. self.nodes[nodeBRootIndex].parent = nodeARootIndex;
  32. self.nodes[nodeARootIndex].size += self.nodes[nodeBRootIndex].size;
  33. return true;
  34. }
  35. fn UnionIteration(self: *UnionFind, area: *const Area) bool {
  36. var performedUnion = false;
  37. for (0 .. @intCast(area.rows)) |row| {
  38. for (0 .. @intCast(area.cols)) |col| {
  39. const nodeAIndex:usize = @intCast(row*@abs(area.cols) + col);
  40. if (area.getCell(@intCast(row), @intCast(col)) == '.') {
  41. if (row > 0 and area.getCell(@intCast(row-1), @intCast(col)) == '.') {
  42. const nodeBIndex: usize = @intCast((row-1)*@abs(area.cols) + col);
  43. if (self.Union(nodeAIndex, nodeBIndex)) {
  44. performedUnion = true;
  45. }
  46. }
  47. if (col > 0 and area.getCell(@intCast(row), @intCast(col-1)) == '.') {
  48. const nodeBIndex: usize = @intCast(row*@abs(area.cols) + col - 1);
  49. if (self.Union(nodeAIndex, nodeBIndex)) {
  50. performedUnion = true;
  51. }
  52. }
  53. if (row < area.rows - 1 and area.getCell(@intCast(row+1), @intCast(col)) == '.') {
  54. const nodeBIndex: usize = @intCast((row+1)*@abs(area.cols) + col);
  55. if (self.Union(nodeAIndex, nodeBIndex)) {
  56. performedUnion = true;
  57. }
  58. }
  59. if (col < area.cols - 1 and area.getCell(@intCast(row), @intCast(col+1)) == '.') {
  60. const nodeBIndex: usize = @intCast(row*@abs(area.cols) + col + 1);
  61. if (self.Union(nodeAIndex, nodeBIndex)) {
  62. performedUnion = true;
  63. }
  64. }
  65. }
  66. }
  67. }
  68. return performedUnion;
  69. }
  70. pub fn init(allocator: std.mem.Allocator, area: *const Area) !UnionFind {
  71. var unionFind: UnionFind = .{
  72. .nodes = try allocator.alloc(UnionFindNode, @intCast(area.rows*area.cols)),
  73. .nodesAllocator = allocator,
  74. };
  75. for (0..unionFind.nodes.len) |i| {
  76. unionFind.nodes[i].parent = i;
  77. unionFind.nodes[i].size = 1;
  78. }
  79. while (true) {
  80. if (!unionFind.UnionIteration(area)) {
  81. break;
  82. }
  83. }
  84. return unionFind;
  85. }
  86. pub fn deinit(self: *const UnionFind) void {
  87. self.nodesAllocator.free(self.nodes);
  88. }
  89. };