(01)-把二元查找树转变成排序的双向链表
题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。要求不能创建任何新的结点,只调整指针的指向。
比如将二元查找树
10
/ \
6 14
/ \ / \
4 8 12 16
转换成双向链表
4=6=8=10=12=14=16。
思路一:当我们到达某一结点准备调整以该结点为根结点的子树时,先调整其左子树将左子树转换成一个排好序的左子链表,再调整其右子树转换右子链表。最近链接左子链表的最右结点(左子树的最大结点)、当前结点和右子链表的最左结点(右子树的最小结点)。从树的根结点开始递归调整所有结点。
思路二:我们可以中序遍历整棵树。按照这个方式遍历树,比较小的结点先访问。如果我们每访问一个结点,假设之前访问过的结点已经调整成一个排序双向链表,我们再把调整当前结点的指针将其链接到链表的末尾。当所有结点都访问过之后,整棵树也就转换成一个排序双向链表了。
思路一对应的代码:
BinaryTreeToList.c
#include <stdio.h>
#include <stdbool.h>
typedef struct Node
{
int m_value;
struct Node *m_pLeft;
struct Node *m_pRight;
}BSTreeNode;
//pNode is the head of sub-tree, asRight is whether pNode is the right child of its parent
//if asRight is true, return the least node in the sub-tree else return the biggest node in the sub-tree
BSTreeNode *ConvertNode(BSTreeNode *pNode, bool asRight)
{
if(!pNode)
{
return NULL;
}
BSTreeNode *pLeft = NULL;
BSTreeNode *pRight = NULL;
if(pNode->m_pLeft)
{
pLeft = ConvertNode(pNode->m_pLeft, false);
}
if(pLeft)
{
pLeft->m_pRight = pNode;
pNode->m_pLeft = pLeft;
}
if(pNode->m_pRight)
{
pRight = ConvertNode(pNode->m_pRight, true);
}
if(pRight)
{
pRight->m_pLeft = pNode;
pNode->m_pRight = pRight;
}
BSTreeNode *pTemp = pNode;
if(asRight)
{
while(pTemp->m_pLeft)
pTemp = pTemp->m_pLeft;
}else{
while(pTemp->m_pRight)
pTemp = pTemp->m_pRight;
}
return pTemp;
}
BSTreeNode *Convert(BSTreeNode *pHeadOfTree)
{
//As we want to return the head of double-link list
//we should set second parameter as true
return ConvertNode(pHeadOfTree, true);
}
void main()
{
int i,j;
BSTreeNode *s;
BSTreeNode *node[7];
for(i = 0; i <7; i++)
{
node[i] = (BSTreeNode *)malloc(sizeof(BSTreeNode));
}
node[0]->m_value = 10;
node[1]->m_value = 6;
node[2]->m_value = 14;
node[3]->m_value = 4;
node[4]->m_value = 8;
node[5]->m_value = 12;
node[6]->m_value = 16;
node[0]->m_pLeft = node[1];
node[0]->m_pRight = node[2];
node[1]->m_pLeft = node[3];
node[1]->m_pRight = node[4];
node[2]->m_pLeft = node[5];
node[2]->m_pRight = node[6];
node[3]->m_pLeft = NULL;
node[3]->m_pRight = NULL;
node[4]->m_pLeft = NULL;
node[4]->m_pRight = NULL;
node[5]->m_pLeft = NULL;
node[5]->m_pRight = NULL;
node[6]->m_pLeft = NULL;
node[6]->m_pRight = NULL;
s = Convert(node[0]);
printf("Last order List: ");
for(j = 0; j <7; j++){
printf("node[%d]=%d ",j,s->m_value);
s = s->m_pRight;
}
}
appendix:
segmentation fault (core dumped) 调试(gdb调试)
http://blog.csdn.net/u011563434/article/details/51199912
写程序经常会遇到这样一个错误:segmentation fault (core dumped)。怎么去解决呢?
首先,就是要知道错误发生的地方。而Linux系统可以产生core文件,配合gdb就可以解决这个问题。
第一步,让系统在信号中断造成的错误时产生core文件
ulimit -c unlimited // 设置core大小为无限
ulimit unlimited //设置文件大小为无限
第二步,编译运行与原来的程序
gcc -o XXX XXX.c -g
./XXX
运行后, ls 发现多出来了core文件
第三步, 用gdb查看core文件
gdb XXX core
然后,输入bt,就会出现错误的位置。如下图
0就是错误的具体位置。具体错误可以从#3到#0来找。这里的错误是fseek第一个参数为0x0,也就是说,文件指针为NULL。再看代码,发现原来文件指针没有释放掉,所以在之后的访问同样文件时,发生了错误。
由此可见,这种调试的方法还是不错的。