描述什么是最小生成树，以及Kruskal算法的工作原理，并编写实现Kruskal算法的Python代码。
最小生成树是一种用于连接有n个节点的无向图的树。它通过选择连接所有节点的边，并且总权重最小化来实现。

Kruskal算法是一种用于寻找无向图的最小生成树的贪心算法。该算法的基本思想是先将所有边按边权值从小到大排序，然后逐步加入边，同时确保每次加入的边都不会构成环。

Kruskal算法的实现：
```python
class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0] * n

    def find(self, x):
        if self.parent[x] == x:
            return x
        self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py:
            return False
        if self.rank[px] < self.rank[py]:
            px, py = py, px
        self.parent[py] = px
        if self.rank[px] == self.rank[py]:
            self.rank[px] += 1
        return True

def kruskal(n, edges):
    uf = UnionFind(n)
    edges.sort(key=lambda x: x[2])
    res = []
    for u, v, w in edges:
        if uf.union(u, v):
            res.append((u, v, w))
            if len(res) == n - 1:
                break
    return res
```