编码技巧之数据结构【笔记】

编码技巧之数据结构【笔记】

数据结构回顾

列表中的数组,链表,队列,栈

树中的二叉树,搜索树,堆/优先队列


图中的无向图,有向图,有向无环图

图的算法中的深度优先遍历,广度优先遍历,拓扑排序和最短路径/最小生成树

树的遍历

二叉树的遍历方法:

前序遍历

先遍历树根,然后前序遍历左子树,然后再前序遍历右子树

中序遍历

先中序遍历左子树,然后遍历树根,然后再中序遍历右子树

后序遍历

先后序遍历左子树,然后后序遍历右子树,然后遍历树根

层次遍历

一层一层的遍历下去,自左向右,自上而下

树的基础代码:

package interview.tree;

public class TreeNode {
private final char value;
private TreeNode left;
private TreeNode right;
private TreeNode parent;

public TreeNode(char value) {
this.value = value;
this.left = null;
this.right = null;
this.parent = null;
}

public char getValue() {
return value;
}

public TreeNode getLeft() {
return left;
}

public void setLeft(TreeNode left) {
this.left = left;
if (this.left != null) {
this.left.setParent(this);
}
}

public TreeNode getRight() {
return right;
}

public void setRight(TreeNode right) {
this.right = right;
if (this.right != null) {
this.right.setParent(this);
}
}

public TreeNode getParent() {
return parent;
}

private void setParent(TreeNode parent) {
this.parent = parent;
}
}

例题一:根据前序中序构造二叉树

我们可以发现左子树前序为BDEG,左子树中序为DBGE

具体代码如下:

package interview.tree;

public class TreeCreator {
public TreeNode createSampleTree() {
TreeNode root = new TreeNode('A');
root.setLeft(new TreeNode('B'));
root.getLeft().setLeft(new TreeNode('D'));
root.getLeft().setRight(new TreeNode('E'));
root.getLeft().getRight().setLeft(new TreeNode('G'));
root.setRight(new TreeNode('C'));
root.getRight().setRight(new TreeNode('F'));
return root;
}

public TreeNode createTree(String preOrder, String inOrder) {
if (preOrder.isEmpty()) {
return null;
}

char rootValue = preOrder.charAt(0);
int rootIndex = inOrder.indexOf(rootValue);

TreeNode root = new TreeNode(rootValue);
root.setLeft(
createTree(
preOrder.substring(1, 1 + rootIndex),
inOrder.substring(0, rootIndex)));
root.setRight(
createTree(
preOrder.substring(1 + rootIndex),
inOrder.substring(1 + rootIndex)));

return root;
}
}

TreeTraversal.java

package interview.tree;

public class TreeTraversal {

public void preOrder(TreeNode root) {
if (root == null) {
return;
}
System.out.print(root.getValue());
preOrder(root.getLeft());
preOrder(root.getRight());
}

public void inOrder(TreeNode root) {
if (root == null) {
return;
}
inOrder(root.getLeft());
System.out.print(root.getValue());
inOrder(root.getRight());
}

public void postOrder(TreeNode root) {
if (root == null) {
return;
}
postOrder(root.getLeft());
postOrder(root.getRight());
System.out.print(root.getValue());
}

public String postOrder(String preOrder, String inOrder) {
if (preOrder.isEmpty()) {
return "";
}

char rootValue = preOrder.charAt(0);
int rootIndex = inOrder.indexOf(rootValue);

return
postOrder(
preOrder.substring(1, 1 + rootIndex),
inOrder.substring(0, rootIndex)) +
postOrder(
preOrder.substring(1 + rootIndex),
inOrder.substring(1 + rootIndex)) +
rootValue;
}

public static void main(String[] args) {
TreeCreator creator = new TreeCreator();
TreeTraversal traversal = new TreeTraversal();

System.out.println("Sample tree traversal");
System.out.println("=====");
TreeNode sampleTree = creator.createSampleTree();
traversal.preOrder(sampleTree);
System.out.println();
traversal.inOrder(sampleTree);
System.out.println();
traversal.postOrder(sampleTree);
System.out.println();

System.out.println("=");
System.out.println("Creating tree from preOrder and inOrder");
System.out.println("
=");
TreeNode tree = creator.createTree("ABDEGCF", "DBGEACF");
traversal.postOrder(tree);
System.out.println();
traversal.postOrder(creator.createTree("", ""));
System.out.println();
traversal.postOrder(creator.createTree("A", "A"));
System.out.println();
traversal.postOrder(creator.createTree("AB", "BA"));
System.out.println();

System.out.println("=");
System.out.println("Generating postOrder directly");
System.out.println("
=");
System.out.println(
traversal.postOrder("ABDEGCF", "DBGEACF"));
System.out.println(
traversal.postOrder("", ""));
System.out.println(
traversal.postOrder("A", "A"));
System.out.println(
traversal.postOrder("AB", "BA"));
}
}

总结:

在思考算法的时候,只要减小问题的规模即可

对于初始值的确定,需要严格地根据递归函数的定义

例题二:寻找中序遍历的时候的下一个结点

具体代码如下:

package interview.tree;

public class InOrder {

public TreeNode next(TreeNode node) {
if (node == null) {
return null;
}

if (node.getRight() != null) {
return first(node.getRight());
} else {
while(node.getParent() != null
&& node.getParent().getRight() == node) {
node = node.getParent();
}
// now we have:
// node.getParent() == null
// || node is left child of its parent
return node.getParent();
}
}

public TreeNode first(TreeNode root) {
if (root == null) {
return null;
}

TreeNode curNode = root;
while(curNode.getLeft() != null) {
curNode = curNode.getLeft();
}
return curNode;
}

public void traverse(TreeNode root) {
for (TreeNode node = first(root);
node != null;
node = next(node)) {
System.out.print(node.getValue());
}
System.out.println();
}

public static void main(String[] args) {
TreeCreator creator = new TreeCreator();
InOrder inOrder = new InOrder();

TreeNode sampleTree = creator.createSampleTree();
inOrder.traverse(sampleTree);

inOrder.traverse(creator.createTree("", ""));
inOrder.traverse(creator.createTree("A", "A"));
inOrder.traverse(creator.createTree("AB", "BA"));
inOrder.traverse(creator.createTree("ABCD", "DCBA"));
inOrder.traverse(creator.createTree("ABCD", "ABCD"));
}
}

总结:

需要注意的是分情况讨论

注意null指针

使用private函数来维护复杂数据结构

posted @ 2021-03-02 13:49  DbWong_0918  阅读(131)  评论(0)    收藏  举报