1. 程式人生 > >關於劍指offer上“二叉搜尋樹與雙向連結串列”題的理解

關於劍指offer上“二叉搜尋樹與雙向連結串列”題的理解

題目描述:

輸入一棵二叉搜尋樹,將該二叉搜尋樹轉換成一個排序的雙向連結串列。要求不能建立任何新的結點,只能調整樹中結點指標的指向。


一、遞迴的思路

對於函式TreeNode* Convert(TreeNode* root),傳入的是需要轉換的二叉樹的頭結點,返回的是已經轉換好的雙向連結串列的頭結點。從root結點來看,以遞迴的思路就是將左孩子和右孩子做黑盒處理,left = Convert(root->left)返回的就是以左孩子為根節點的樹已經轉化好的雙向連結串列的頭結點,right = Convert(root->right)返回的就是以右孩子為根節點的樹已經轉化好的雙向連結串列的頭結點,只要left和right不為空,使用left找到左孩子雙向連結串列的最後一個結點node,將node,root,right一連線,問題解決!


步驟:

1、根節點為root,遞迴root的左孩子,將左子樹構成雙向連結串列,並返回連結串列頭結點left

2、使用left頭結點遍歷到左子樹雙鏈表的最後一個結點node

3、如果左子樹連結串列不為空,將node和root連線起來

4、同理將右子樹構成雙向連結串列,並返回連結串列頭結點right

5、如果右子樹連結串列不為空,將root和right連線起來

6、如果left不為空,返回left,否則返回root


程式碼如下:

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    TreeNode* Convert(TreeNode* root)
    {
        if(root == NULL){
            return NULL;
        }
        if(root->left == NULL && root->right == NULL){
            return root;
        }
        //1、根節點為root,遞迴root的左孩子,將左子樹構成雙向連結串列,並返回連結串列頭結點left
        TreeNode* left = Convert(root->left);
        TreeNode* node = left;
        //2、使用left頭結點遍歷到左子樹雙鏈表的最後一個結點node
        while(node != NULL && node->right != NULL){
            node = node->right;
        }//while
        //3、如果左子樹連結串列不為空,將node和root連線起來
        if(left != NULL){
            node->right = root;
            root->left = node;
        }
        //4、同理將右子樹構成雙向連結串列,並返回連結串列頭結點right
        TreeNode* right = Convert(root->right);
        //5、如果右子樹連結串列不為空,將root和right連線起來
        if(right != NULL){
            root->right = right;
            right->left = root;
        }
        //6、如果left不為空,返回left,否則返回root
        return left == NULL?root:left;
    }
};


二、非遞迴思路

按照二叉樹中序遍歷非遞迴的思路


程式碼:

struct TreeNode{
    int val;
    TreeNode* left;
    TreeNode* right;
};

//對比,二叉樹的非遞迴中序遍歷求法
void inorder(TreeNode* root){
    //非遞迴版中序遍歷
    if(NULL == root){
        return;
    }
    stack<TreeNode*> data;
    TreeNode* node = root;
    while(node!=NULL || !data.empty()){
        while(node != NULL){
            data.push(node);
            node = node->left;
        }//while
        if(!data.empty()){
            node = data.top();
            data.pop();
            cout<<node->val<<endl;
            node = node->right;
        }
    }//while
    return;
}

TreeNode* Convert(TreeNode* root){
    if(NULL == root){
        return NULL;
    }
    if(root->left == NULL && root->right == NULL){
        return root;
    }
    stack<TreeNode*> data;
    TreeNode* node = root;
    TreeNode* pre = NULL;  //用於儲存中序遍歷序列的上一個結點
    bool isFirst = true;
    while(node != NULL || !data.empty()){
        while(node != NULL){
            data.push(node);
            node = node->left;
        }
        node = data.top();
        data.pop();
        if(isFirst){
            root = node;   //將中序遍歷中的第一個結點記為root
            pre = root;
            isFirst = false;
        }else{
            pre->right = node;
            node->left = pre;
            pre = node;
        }
        node = node->right;
    }
    return root;
}


牛客網題目地址:

https://www.nowcoder.com/practice/947f6eb80d944a84850b0538bf0ec3a5?tpId=13&tqId=11179&rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking