二叉查找樹轉變爲排序的雙向鏈表

問題:對於輸入的一棵二叉查找樹,將該二叉查找樹轉換成一個排序的雙向鏈表,要求不能創建任何新的結點,只調整指針的指向來達到目的。

目測這個問題不難解決,應該可以在O(n)的時間複雜度內解決。對於一個二叉查找樹,轉換爲一個從小到大排序的鏈表,那麼根節點的左兒子及其子孫都會在根節點的前面,根節點的右兒子及其子孫都會在根節點的後面。這樣,一個遞歸的算法便可以解決問題。按照這個思路我把代碼寫了出來,驗證結果沒有問題。

行28-70的代碼就是完成轉換的方法,vlr是包含兩個指針的數組,vlr[0]指向root這棵樹轉換完後的鏈表頭,vlr[1]指向鏈表尾。

#include <iostream>
#include <string>
using namespace std;

struct tree {
	int value;
	struct tree *lchild;
	struct tree *rchild;
};

struct tree *insert(struct tree *root, int value)
{
	if (root) {
		if (value < root->value) {
			root->lchild = insert(root->lchild, value);
		} else {
			root->rchild = insert(root->rchild, value);
		}
	} else {
		root = new struct tree;
		root->value = value;
		root->lchild = 0;
		root->rchild = 0;
	}
	return root;
}

struct tree *convert_tree(struct tree *root, struct tree *vlr[2])
{
	if (root) {
		struct tree *lrl[2] = {0, 0}, *lrr[2] = {0, 0};
		convert_tree(root->lchild, lrl);
		convert_tree(root->rchild, lrr);
		if (lrl[0]) {
		    if (lrr[0]) {
		        vlr[0] = lrl[0];
		        vlr[1] = lrr[1];
		        root->lchild = lrl[1];
		        root->rchild = lrr[0];
		        lrl[0]->lchild = lrr[1];
		        lrl[1]->rchild = root;
		        lrr[0]->lchild = root;
		        lrr[1]->rchild = lrl[0];
		    } else {
		        vlr[0] = lrl[0];
		        vlr[1] = root;
		        root->lchild = lrl[1];
		        root->rchild = lrl[0];
		        lrl[0]->lchild = root;
		        lrl[1]->rchild = root;
		    }
		} else {
		    if (lrr[0]) {
		        vlr[0] = root;
		        vlr[1] = lrr[1];
		        root->lchild = lrr[1];
		        root->rchild = lrr[0];
		        lrr[0]->lchild = root;
		        lrr[1]->rchild = root;
		    } else {
		        vlr[0] = root;
		        vlr[1] = root;
		        root->lchild = root;
		        root->rchild = root;
		    }
		}
		root = vlr[0];
	}
	return root;
}

struct tree *convert(struct tree *root)
{
	struct tree *list[2] = {0, 0};
	return convert_tree(root, list);
}

void print_tree_prefix(struct tree *root, string pfx)
{
	if (root) {
		if (root->lchild) {
		    cout << pfx << "|" << endl;
		    if (root->rchild)
		        cout << pfx << "|-<L> " << root->lchild->value << endl;
		    else
		        cout << pfx << "`-<L> " << root->lchild->value << endl;
		    print_tree_prefix(root->lchild, pfx + "|     ");
		}
		if (root->rchild) {
		    cout << pfx << "|" << endl;
		    cout << pfx << "`-<R> " << root->rchild->value << endl;
		    print_tree_prefix(root->rchild, pfx + "      ");
		}
	}
}

void print_tree(struct tree *root)
{
    if (root) {
	    cout << root->value << endl;
	    print_tree_prefix(root, "");
	}
}

void print_list(struct tree *root)
{
	struct tree *next = root;
	if (next) {
		cout << "list : ";
	    do {
		    cout << next->value;
		    next = next->rchild;
		    if (next != root)
		        cout << " <-> ";
	    } while (next != root);
		cout << "." << endl;
	}
}

int main()
{
	struct tree *root = 0;
	root = insert(root, 100);
	root = insert(root, 233);
	root = insert(root,  33);
	root = insert(root,  67);
	root = insert(root, 104);
	root = insert(root,  34);
	root = insert(root,  32);
	root = insert(root, 766);
	root = insert(root, 456);
	print_tree(root);
	
	root = convert(root);
	print_list(root);
	
	return 0;
}

100
|
|-<L> 33
|     |
|     |-<L> 32
|     |
|     `-<R> 67
|           |
|           `-<L> 34
|
`-<R> 233
      |
      |-<L> 104
      |
      `-<R> 766
            |
            `-<L> 456
對於這樣一棵樹,輸出的結果爲
list : 32 <-> 33 <-> 34 <-> 67 <-> 100 <-> 104 <-> 233 <-> 456 <-> 766.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章