剑指Offer——从尾到头打印链表与重建二叉树

剑指offer系列,个人读书记录,希望能帮助你理解。

变秃才能变强

具体的实现思路,在我的代码注释中全都有,如果还不理解可以多刷几遍。

谜底就在迷面上,就问你刺不刺激——岳云鹏

从尾到头打印链表

从尾到头打印链表github地地址

//
// Created by android on 19-8-9.
//
/* 输入一个链表,从尾到头打印链表每个节点的值
 * 实现
 * 思路:从前向后记录‘ ’数目,从后向前替换‘ ’。 重点:从后向前替换的时候的技巧 例如:“we are lucky”
 * (1) 从头到尾输出比较简单,一种想法是反转结点的指针。但是会破坏原链表的结构,不推荐;
 * (2) 从头遍历链表,先访问的后输出,后访问的先输出,“后进先出”,利用栈来实现;
 * (3) 递归本质上就是一个栈的结构,可以利用递归来实现。
 * 但是当链表比较长的时候,递归会导致函数调用的层级很深,有可能会导致函数调用栈的溢出,故还是推荐使用栈来实现。
 * */
#include
#include
#include
#include 
#include 

using namespace std;

typedef int ElementType;

typedef struct ListNode {
    ElementType Element;        //    数据域,存放数据
    ListNode *Next;        //    指向下一个链表节点
};

ListNode *createListNode(int value) {
    ListNode *pNode = new ListNode();
    pNode->Element = value;
    pNode->Next = nullptr;
    return pNode;
}

void connectListNodes(ListNode *pCurrent, ListNode *pNext) {
    if (pCurrent == nullptr) {
        printf("Error to connect two nodes.\n");
        exit(1);
    }
    pCurrent->Next = pNext;
}

class Solution {
public:
    //using stack
    void printListReversingly(ListNode *pHead) {
        stack nodes;
        ListNode *pNode = pHead;
        while (pNode != nullptr) {
            nodes.push(pNode);
            pNode = pNode->Next;
        }
        while (!nodes.empty()) {
            pNode = nodes.top();
            printf("%d\t", pNode->Element);
            nodes.pop();

        }
    }

    void printListRever_Recursively(ListNode *pHead) {
        if (pHead != nullptr) {
            if (pHead->Next != nullptr) {
                printListRever_Recursively(pHead->Next);
            }
            printf("%d\t", pHead->Element);
        }
    }
};

TEST(print, a1) {

    ListNode *pNode1 = createListNode(1);
    ListNode *pNode2 = createListNode(2);
    ListNode *pNode3 = createListNode(3);
    ListNode *pNode4 = createListNode(4);
    ListNode *pNode5 = createListNode(5);

    connectListNodes(pNode1, pNode2);
    connectListNodes(pNode2, pNode3);
    connectListNodes(pNode3, pNode4);
    connectListNodes(pNode4, pNode5);

    (new Solution)->printListReversingly(pNode1);

    (new Solution)->printListRever_Recursively(pNode1);

}

重建二叉树

重建二叉树

//
// Created by android on 2019/8/11.
//

/*
前序遍历:
    1.访问根节点
    2.前序遍历左子树
    3.前序遍历右子树
中序遍历:
    1.中序遍历左子树
    2.访问根节点
    3.中序遍历右子树
后序遍历:
    1.后序遍历左子树
    2.后序遍历右子树
    3.访问根节点
 *题目:
 * 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
 * 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
 *思路分析
 * 根据二叉树前序遍历的特点(根-左-右),每次读取的第一个值一定是根节点,这样我们可以在中序遍历的序列中找到当前的根节点的位置。
 * 根据中序遍历的特点(左-根-右),当确定了一个根节点后,其左边序列就是这个根节点的左子树,右边序列就是其右子树。
 * 我们每次都需要在前序遍历中找根节点并创建一个根节点,然后在中序遍历中确定根节点位置,并确定当前根节点的左右子树,
 * 然后以同样的方法去构建左右子树。
 * 这整个过程其实是一个递归的过程。
 */
#include 
#include 

using namespace std;
typedef int ElementType;

typedef struct BinaryTreeNode {
    ElementType elementType;
    BinaryTreeNode *pLeftBinaryTreeNode;
    BinaryTreeNode *pRightBinaryTreeNode;
};

BinaryTreeNode *CreateBinaryTreeNode(int value) {
    BinaryTreeNode *pNode = new BinaryTreeNode();
    pNode->elementType = value;
    pNode->pRightBinaryTreeNode = pNode->pLeftBinaryTreeNode = nullptr;
    return pNode;
}

void ConnectTreeNodes(BinaryTreeNode *pParent, BinaryTreeNode *pLeft, BinaryTreeNode *pRight) {
    if (pParent != nullptr) {
        pParent->pLeftBinaryTreeNode = pLeft;
        pParent->pRightBinaryTreeNode = pRight;
    }
}


BinaryTreeNode *constructCore(int *startPreOrder, int *endPreOrder, int *startInOrder, int *endInOrder) {
    //前序遍历第一个书为root
    int rootValue = startPreOrder[0];
    BinaryTreeNode *root = new BinaryTreeNode();
    root->elementType = rootValue;
    root->pLeftBinaryTreeNode = root->pRightBinaryTreeNode = nullptr;

    if (startPreOrder == endPreOrder) {
        if (startInOrder == endInOrder && *startPreOrder == *startInOrder)
            return root;
        else
            throw exception();
    }
    // 在中序遍历中找到根结点的值
    int *rootInOrder = startInOrder;
    while (rootInOrder <= endInOrder && *rootInOrder != rootValue)
        ++rootInOrder;

    if (rootInOrder == endInOrder && *rootInOrder != rootValue)
        throw exception();

    int leftLength = rootInOrder - startInOrder;
    int *leftPreOrderEnd = startPreOrder + leftLength;
    if (leftLength > 0) {
        // 构建左子树
        root->pLeftBinaryTreeNode = constructCore(startPreOrder + 1, leftPreOrderEnd,
                                                  startInOrder, rootInOrder - 1);
    }
    if (leftLength < endPreOrder - startPreOrder) {
        // 构建右子树
        root->pRightBinaryTreeNode = constructCore(leftPreOrderEnd + 1, endPreOrder,
                                                   rootInOrder + 1, endInOrder);
    }

    return root;
};

BinaryTreeNode *construct(int *preOrder, int *inOrder, int length) {
    if (preOrder == nullptr || inOrder == nullptr || length <= 0)
        return nullptr;

    return constructCore(preOrder, preOrder + length - 1,
                         inOrder, inOrder + length - 1);

}

class Solution {
public:
    BinaryTreeNode *reConstructBinaryTree(int *preOrder, int *inOrder, int length) {
        return construct(preOrder, inOrder, length);
    }
};

TEST(construct, test) {
    const int LENGTH = 8;
    int preOrder[LENGTH] = {1, 2, 4, 7, 3, 5, 6, 8};
    int inOrder[LENGTH] = {4, 7, 2, 1, 5, 3, 8, 6};
    BinaryTreeNode *root = (new Solution)->reConstructBinaryTree(preOrder, inOrder, LENGTH);
    EXPECT_EQ(1, root->elementType);

}

你可能感兴趣的:(剑指Offer——从尾到头打印链表与重建二叉树)