二叉树的垂序遍历
Posted HelloCoding08
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树的垂序遍历相关的知识,希望对你有一定的参考价值。
leetcode 第987题
给你二叉树的根结点 root ,请你设计算法计算二叉树的 垂序遍历 序列。
对位于 (row, col) 的每个结点而言,其左右子结点分别位于 (row + 1, col - 1) 和 (row + 1, col + 1) 。树的根结点位于 (0, 0) 。
二叉树的 垂序遍历 从最左边的列开始直到最右边的列结束,按列索引每一列上的所有结点,形成一个按出现位置从上到下排序的有序列表。如果同行同列上有多个结点,则按结点的值从小到大进行排序。
返回二叉树的 垂序遍历 序列。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:[[9],[3,15],[20],[7]]
解释:
列 -1 :只有结点 9 在此列中。
列 0 :只有结点 3 和 15 在此列中,按从上到下顺序。
列 1 :只有结点 20 在此列中。
列 2 :只有结点 7 在此列中。
示例 2:
输入:root = [1,2,3,4,5,6,7]
输出:[[4],[2],[1,5,6],[3],[7]]
解释:
列 -2 :只有结点 4 在此列中。
列 -1 :只有结点 2 在此列中。
列 0 :结点 1 、5 和 6 都在此列中。
1 在上面,所以它出现在前面。
5 和 6 位置都是 (2, 0) ,所以按值从小到大排序,5 在 6 的前面。
列 1 :只有结点 3 在此列中。
列 2 :只有结点 7 在此列中。
typedef int ElemType;
typedef struct node Node;
typedef struct node* Tree;
struct node {
ElemType elem;
Node* lchild;
Node* rchild;
};
//创建树
Tree create_tree (FILE* fp) {
Tree tree;
ElemType elem;
fscanf(fp, "%d", &elem);
if (0 == elem) {
return NULL;
} else {
tree = (Node*)malloc(sizeof(Node));
tree->elem = elem;
tree->lchild = create_tree(fp);
tree->rchild = create_tree(fp);
}
return tree;
}
//打印二维数组
void show (int** array, int rows, const int* cols) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols[i]; j++) {
printf("%d\t", array[i][j]);
}
printf("\n");
}
}
//qsort的比较函数
int compare (const void* a, const void* b) {
int* m = *(int**)a;
int* n = *(int**)b;
//先按照纵坐标排序
if (m[2] != n[2]) {
return m[2] - n[2];
}
//如果纵坐标相对, 再按照横坐标排序
if (m[1] != n[1]) {
return m[1] - n[1];
}
//如果坐标一样,再按照值排序
return m[0] - n[0];
}
//计算树结点的个数
int get_node_nums (Tree tree) {
if (tree == NULL) {
return 0;
}
int lnode = get_node_nums(tree->lchild);
int rnode = get_node_nums(tree->rchild);
//左节点的个数加上右节点的个数再加上根节点
return lnode + rnode + 1;
}
void dfs (Tree tree, int rows, int cols, int** matrix, int* index) {
if (tree == NULL) {
return;
}
//节点的值
matrix[*index][0] = tree->elem;
//节点的横坐标
matrix[*index][1] = rows;
//节点的纵坐标
matrix[*index][2] = cols;
(*index)++;
dfs(tree->lchild, rows + 1, cols - 1, matrix, index);
dfs(tree->rchild, rows + 1, cols + 1, matrix, index);
}
int** vertical_traversal (Tree tree, int* return_size, int** return_column_sizes) {
//创建一个3元组
//每个数组的长度都是3,
//第1个值表示节点的值,第2个和第3个值表示节点的横坐标和竖坐标
int matrix_rows = get_node_nums(tree);
int* matrix_cols = (int*)malloc(sizeof(int) * matrix_rows);
for (int i = 0; i < matrix_rows; i++) {
matrix_cols[i] = 3;
}
int** matrix = (int**)malloc(sizeof(int*) * matrix_rows);
for (int i = 0; i < matrix_rows; i++) {
matrix[i] = (int*)malloc(sizeof(int) * matrix_cols[i]);
}
//result的索引
int index = 0;
//计算所有节点的值和坐标,根节点的坐标是(0,0)
dfs(tree, 0, 0, matrix, &index);
printf("sort before\n");
show(matrix, matrix_rows, matrix_cols);
qsort(matrix, matrix_rows, sizeof(int*), compare);
printf("sort after\n");
show(matrix, matrix_rows, matrix_cols);
//排序后,最大值减去最小值,总共有这么多种情况
int rows = matrix[matrix_rows - 1][2] - matrix[0][2] + 1;
int** result = (int**)malloc(sizeof(int*) * rows);
*return_size = 0;
*return_column_sizes = (int*)malloc(sizeof(int) * rows);
int i = 0;
while (i < matrix_rows) {
int j = i + 1;
//横坐标相同的个数
int num = 1;
while (j < matrix_rows && matrix[i][2] == matrix[j][2]) {
num++;
j++;
}
result[*return_size] = (int*)malloc(sizeof(int) * num);
for (int k = 0; k < num; k++) {
result[*return_size][k] = matrix[i + k][0];
}
(*return_column_sizes)[*return_size] = num;
(*return_size)++;
i = j;
}
return result;
}
void per_order (Tree tree) {
if (tree == NULL) {
return;
}
per_order(tree->lchild);
printf("%d\t", tree->elem);
per_order(tree->rchild);
}
int main() {
char path[] = "F:\\C\\VerticalTraversal\\987.txt";
FILE* fp = fopen(path, "r");
if (fp == NULL) {
perror("file open error");
exit(-1);
}
Tree tree = create_tree(fp);
fclose(fp);
per_order(tree);
printf("\n");
int rows;
int* cols;
int** result = vertical_traversal(tree, &rows, &cols);
printf("show result\n");
show(result, rows, cols);
return 0;
}
以上是关于二叉树的垂序遍历的主要内容,如果未能解决你的问题,请参考以下文章