[Algorithm]树与二叉树

一.树与二叉树相关算法


1.二叉树按顺序结构存储,求编号为i和j的两个结点的最近公共祖先结点的值

1 ElemType CommonAncestor( SeqTree T, int i, int j )
2 {
3     while ( i != j )
4     {
5         if ( i > j ) i /= 2;
6         else j /= 2;
7     }
8     return T[i];
9 }

2.二叉树前序遍历非递归算法

 1 void PreOrder( BiTree T )
 2 {
 3     BiTree S[MAXSIZE], p;
 4     int top = -1;
 5     p = T;
 6     while ( p || top != -1 )
 7     {
 8         if (p)
 9         {
10             visit( p );
11             S[++top] = p; p = p->lchild;
12         }
13         else
14         {
15             p = S[top--]; p = p->rchild;
16         }
17     }
18 }

3.二叉树中序遍历非递归算法

 1 void InOrder( BiTree T )
 2 {
 3     BiTree S[MAXSIZE], p;
 4     int top = -1;
 5     p = T;
 6     while ( p || top != -1 )
 7     {
 8         if (p )
 9         {
10             S[++top] = p; p = p->lchild;
11         }
12         else
13         {
14             p = S[top--]; visit( p ); p = p->rchild;
15         }
16     }
17 }

4.二叉树后序遍历非递归算法

 1 void PostOrder( BiTree T )
 2 {
 3     BiTree Q[MAXSIZE], p, r;
 4     int top = -1;
 5     p = T; r = NULL;
 6     while ( p || top != -1 )
 7     {
 8         if (p)    // 走到最左边
 9         {
10             S[++top] = p; p = p->lchild;
11         }
12         else    // 向右
13         {
14             p = S[top];
15             if (p->rchild&&p->rchild!=r)    // 转向右
16                 p = p->rchild;
17             else    // 根
18             {
19                 p = S[top--];
20                 visit( p );
21                 r = p;
22                 p = NULL;
23             }
24         }
25     }
26 }

5.二叉树层次遍历算法

 1 void LevelOrder( BiTree T )
 2 {
 3     BiTree Q[MAXSIZE], p;
 4     int front = -1, rear = -1;
 5     Q[++rear] = T;
 6     while ( front != rear )
 7     {
 8         p = Q[++front];
 9         visit( p );
10         if ( p->lchild ) Q[++rear] = p->lchild;
11         if ( p->rchild ) Q[++rear] = p->rchild;
12     }
13 }

6.二叉树的自下而上,从右到左的层次遍历算法

 1 void InvertLevel( BiTree T )
 2 {
 3     BiTree S[MAXSIZE], Q[MAXSIZE], p;
 4     int front = -1, rear = -1, top = -1;
 5     Q[++rear] = T;
 6     while ( front != rear )
 7     {
 8         p = Q[++front];
 9         S[++top] = p;
10         if ( p->lchild ) Q[++rear] = p->lchild;
11         if ( p->rchild ) Q[++rear] = p->rchild;
12     }
13     while ( top!=-1 )
14     {
15         p = S[top--]; visit( p );
16     }
17 }

7.求二叉树高度(递归)

1 int BtDepth( BiTree T )
2 {
3     if ( T == NULL ) return 0;
4     int ldepth, rdepth;
5     ldepth = BtDepth( T->lchild );
6     rdepth = BtDepth( T->rchild );
7     return ldepth > rdepth ? ldepth + 1 : rdepth + 1;
8 }

8.求二叉树高度(非递归)

 1 // 法一思路:后序遍历,最大栈长即为树的高度
 2 int BtDepth( BiTree T )
 3 {
 4     BiTree S[MAXSIZE], p, r;
 5     int top = -1, depth = 0;
 6     while ( p || top != -1 )
 7     {
 8         if ( p )
 9         {
10             S[++top] = p; p = p->lchild;
11         }
12         else
13         {
14             p = S[top];
15             if ( p->rchild&&p->rchild != r )
16                 p = p->rchild;
17             else
18             {
19                 if (top+1>depth)
20                     depth = top + 1;
21                 p = S[top--];
22                 r = p;
23                 p = NULL;
24             }
25         }
26     }
27     return depth;
28 }
 1 // 法二思路:层次遍历,层数即为高度
 2 int BtDepth( BiTree T )
 3 {
 4     BiTree Q[MAXSIZE], p;
 5     int front = -1, rear = -1, last = 0, depth = 0;
 6     Q[++rear] = T;
 7     while ( front != rear )
 8     {
 9         p = Q[++front];
10         if ( p->lchild )
11             Q[++rear] = p->lchild;
12         if ( p->rchild )
13             Q[++rear] = p->rchild;
14         if ( front == last )
15         {
16             depth++;
17             last = rear;
18         }
19     }
20     return depth;
21 }

9.先许遍历序列和中序遍历序列分别存放于两个一维数组$A[1...n],B[1...n]$中,编写算法建立该二叉树的二叉链表

 1 BiTree PreInCreate( ElemType A[], ElemType B[], int l1, int h1, int l2, int h2 )
 2 {
 3     BiTree root = ( BiTree ) malloc( sizeof( BiTNode ) );
 4     int i, llen, rlen;
 5     root->data = A[l1];
 6     for ( i = l2; B[i] != root->data; i++ );
 7     llen = i - l2;
 8     rlen = h2 - i;
 9     if ( llen )
10         root->lchild = PreInCreate( A, B, l1 + 1, l1 + llen, l2, l2 + llen - 1 );
11     else
12         root->rchild = NULL;
13     if ( rlen )
14         root->rchild = PreInCreate( A, B, h1 - rlen + 1, h1, h2 - rlen + 1, h2 );
15     else
16         root->rchild = NULL;
17     return root;
18 }

 10.判断二叉树是否是完全二叉树

 1 bool IsComplete( BiTree T )
 2 {
 3     if ( T == NULL ) return true;
 4     BiTree Q[MAXSIZE], p;
 5     int front = -1, rear = -1;
 6     Q[++rear] = T;
 7     while ( front != rear )
 8     {
 9         p = Q[++front];
10         if (p)
11         {
12             Q[++rear] = p->lchild;
13             Q[++rear] = p->rchild;
14         } 
15         else
16         {
17             while ( front != rear )
18             {
19                 p = Q[++front];
20                 if ( p ) return false;
21             }
22         }
23     }
24     return true;
25 }

11.计算一棵给定二叉树的所有双分支结点个数

1 int N2Nodes( BiTree T )
2 {
3     if ( T == NULL ) return 0;
4     if ( T->lchild && T->rchild )
5         return N2Nodes( T->lchild ) + N2Nodes( T->rchild ) + 1;
6     return N2Nodes( T->lchild ) + N2Nodes( T->rchild );
7 }

12.将二叉树中所有结点的左,右子树进行交换

1 void SwapTree( BiTree T )
2 {
3     if ( T == NULL ) return;
4     SwapTree( T->lchild );
5     SwapTree( T->rchild );
6     swap( T->lchild, T->rchild );
7 }

13.求二叉树先序遍历序列中第$k(1le kle ext 二叉树结点个数)$个结点的值

 1 int i = 1;
 2 ElemType PreNodeK( BiTree T, int k )
 3 {
 4     if ( T == NULL ) return '#';
 5     if ( i == k ) return T->data;
 6     i++;    // 下一个结点
 7     ElemType ch = PreNodeK( T->lchild, k );
 8     if ( ch != '#' ) return ch;
 9     ch = PreNodeK( T->rchild, k );
10     return ch;
11 }

14.二叉树中,对于每一个元素值为x的结点,删去以它为根的子树,并释放相应的空间

1 void DeleteNode( BiTree T )
2 {
3     if ( T == NULL ) return;
4     DeleteNode( T->lchild );
5     DeleteNode( T->rchild );
6     free( T );
7 }
 1 // 法一:递归
 2 void DeleteAllXNode( BiTree T, ElemType x )
 3 {
 4     if ( T == NULL ) return;
 5     if ( T->data == x )
 6     {
 7         DeleteNode( T ); return;
 8     }
 9     DeleteAllXNode( T->lchild, x );
10     DeleteAllXNode( T->rchild, x );
11 }
 1 // 法二:非递归
 2 void DeleteAllXNode( BiTree T, ElemType x )
 3 {
 4     if ( T == NULL ) return;
 5     BiTree Q[MAXSIZE], p;
 6     int front = -1, rear = -1;
 7     Q[++rear] = T;
 8     while ( front != rear )
 9     {
10         p = Q[++front];
11         if ( p->data == x ) DeleteNode( p );
12         else
13         {
14             if ( p->lchild ) Q[++rear] = p->lchild;
15             if ( p->rchild ) Q[++rear] = p->rchild;
16         }
17     }
18 }

15.输出二叉树中值为x的结点$(le 1)$个的所有祖先

 1 // 法一:递归
 2 bool AllAncestorX( BiTree T, ElemType x )
 3 {
 4     if ( T == NULL ) return false;
 5     if ( T->data == x ) return true;
 6     bool b1, b2;
 7     b1 = AllAncestorX( T->lchild, x );
 8     b2 = AllAncestorX( T->rchild, x );
 9     if ( b1 || b2 ) visit( T );
10     return b1 || b2;
11 }
 1 // 法二:非递归
 2 // 思路: 后序遍历非递归方式中,保留在栈中所有元素(除栈顶外)必然是栈顶的祖先结点,只要找到x结点,将所有结点出栈即可
 3 void AllAncestorX( BiTree T, ElemType x )
 4 {
 5     if ( T == NULL ) return;
 6     BiTree S[MAXSIZE], p, r;
 7     int top = -1;
 8     p = T; r = NULL;
 9     while ( p||top!=-1 )
10     {
11         if (p)
12         {
13             S[++top] = p; p = p->lchild;
14         }
15         else
16         {
17             p = S[top];
18             if ( p->rchild&&p->rchild != r )
19                 p = p->rchild;
20             else
21             {
22                 p = S[top--];
23                 if (p->data==x)
24                 {
25                     while ( top != -1 )
26                     {
27                         p = S[top--]; visit( p );
28                     }
29                 }
30                 r = p;
31                 p = NULL;
32             }
33         }
34     }
35 }

16.p,q为二叉树中任意两个结点的指针,编写算法找到p,q的最近公共祖先结点(递归)

 1 // 思路:   ①左子树中能找到p(或q),右子树中能找到q(或p),的结点一定为p,q的最近公共结点
 2 //        ②p,q都在右子树上,则深度低的为公共祖先
 3 //        ③p,q都在左子树上,则深度低的为公共祖先
 4 //    三种情况       o  <-root(此时为公共祖先)      o  <-root                             o <-root
 5 //                /                                                                /
 6 //           p-> o   o  <-q                       o  <-p(此时为公共祖先为right)        o  <-p(此时为公共祖先left)
 7 //                                                                                /
 8 //                                                  o  <-q                        o  <-q
 9 BiTree Ancestor( BiTree root, BiTNode *p, BiTNode *q )
10 {
11     if ( !root || !p || !q ) return NULL;
12     if ( p == root || q == root ) return root;
13     BiTree left, right;
14     /* 
15      * ①在左子树中,若找到p,q中一个,则返回一个
16      * ②在左子树中,若找到p,q(全),则返回较近的一个(高度较低的)
17      */
18     left = Ancestor( root->lchild, p, q );
19     /*
20     * ①在右子树中,若找到p,q中一个,则返回一个
21     * ②在右子树中,若找到p,q(全),则返回较近的一个(高度较低的)
22     */
23     right = Ancestor( root->rchild, p, q );    
24     if ( left&&right ) return root;
25     return left ? left : right;
26 }

17.求非空二叉树的宽度

 1 int TreeWidth( BiTree T )
 2 {
 3     BiTree Q[MAXSIZE], p;
 4     int front = -1, rear = -1, maxWidth = 0;
 5     Q[++rear] = T;
 6     while ( front != rear )
 7     {
 8         int width = rear - front;
 9         if ( maxWidth < width )
10             maxWidth = width;
11         while ( width-- )
12         {
13             p = Q[++front];
14             if ( p->lchild ) Q[++rear] = p->lchild;
15             if ( p->rchild ) Q[++rear] = p->rchild;
16         }
17     }
18     return maxWidth;
19 }

18.一棵满二叉树(所有结点值均不同),已知其先序序列为pre,设计算法求其后序序列post

 1 // 思路: 每次都会确定出后序的一个位置并划分为左右两块,再分别在这左右两块中继续确定其他元素 
 2 //  先序: x|    |    |
 3 //  后序: |    |    |x
 4 void PreToPost( ElemType pre[], int l1, int h1, ElemType post[], int l2, int h2 )
 5 {
 6     if ( h1 < l1 ) return;
 7     post[h2] = pre[l1]; // 确定出一个后序位置
 8     int half = ( h1 - l1 ) / 2;
 9     PreToPost( pre, l1 + 1, l1 + half, post, l2, l2 + half - 1 );
10     PreToPost( pre, h1 - half + 1, h1, post, h2 - half, h2 - 1 );
11 }

19.将二叉树叶子结点按从左到右连成单链表,表头指针为head,叶结点的右指针域存放单链表指针

 1 BiTree head, pre = NULL;
 2 BiTree InOrder( BiTree bt )
 3 {
 4     if ( bt == NULL ) return NULL;
 5     InOrder( bt->lchild );
 6     if ( !bt->lchild && !bt->rchild )
 7     {
 8         if (!pre)
 9         {
10             head = pre = bt;
11         }
12         else
13         {
14             pre->rchild = bt; pre = bt;
15         }
16     }
17     InOrder( bt->rchild );
18     pre->rchild = NULL;
19     return head;
20 }

20.判断两棵二叉树是否相似.(注:不要求结点值相同,只要树的外形相同即可)

 1 bool Similar( BiTree T1, BiTree T2 )
 2 {
 3     if ( T1 == NULL && T2 == NULL ) 
 4         return true;
 5     else if ( T1 == NULL || T2 == NULL ) 
 6         return false;
 7     else if ( Similar( T1->lchild, T2->lchild ) && Similar( T1->rchild, T2->rchild ) )
 8         return true;
 9     return false;
10 }

21.将表达式树转换为等价的中缀表达式(通过括号反映操作符的计算次序)并输出

 1 // 思路: 表达式树的中序序列加上必要的括号即为等价的中缀表达式.除根结点外,遍历到其他结点时在遍历其左子树之前加上左括号,在遍历完右子树后加上右括号
 2 void BiTreeToExp( BiTree T, int deep )
 3 {
 4     if ( T == NULL ) return;
 5     else if ( !T->lchild && !T->rchild ) visit( T );
 6     else
 7     {
 8         if ( deep > 1 ) printf( "(" );
 9         BiTreeToExp( T->lchild, deep + 1 );
10         visit( T );
11         BiTreeToExp( T->rchild, deep + 1 );
12         if ( deep > 1 ) printf( "(" );
13     }
14 }

22.求孩子兄弟表示法存储的森林的叶子节点数

 1 typedef struct CSNode
 2 {
 3     ElemType data;
 4     struct CSNode *firstchild, *nextsibling;
 5 }CSNode, *CSTree;
 6 
 7 int Leaves( CSTree T )
 8 {
 9     if ( T == NULL ) return 0;
10     if ( T->firstchild == NULL )
11         return 1 + Leaves( T->nextsibling );
12     else
13         return Leaves( T->firstchild ) + Leaves( T->nextsibling );
14 }

23.以孩子兄弟链表为存储结构,求树的高度(深度)(递归)

1 int Height( CSTree T )
2 {
3     if ( T == NULL ) return 0;
4     int hc, hs;
5     hc = Height( T->firstchild ) + 1;
6     hs = Height( T->nextsibling );
7     return hc > hs ? hc : hs;
8 }

24.二叉排序树的查找(非递归)

 1 BiTree BSTSearch( BiTree T, ElemType key )
 2 {
 3     while ( T && key != T->data )
 4     {
 5         if ( key < T->data )
 6             T = T->lchild;
 7         else
 8             T = T->rchild;
 9     }
10     return T;
11 }

 1 BiTree BSTSearch( BiTree T, ElemType key )
 2 {
 3     while ( T )
 4     {
 5         if ( T->data == key ) return T;
 6         else if ( T->data > key )
 7             T = T->lchild;
 8         else
 9             T = T->rchild;
10     }
11     return T;
12 }

25.二叉排序树的插入(递归)

 1 bool BSTInsert( BiTree& T, ElemType key )
 2 {
 3     if (!T)
 4     {
 5         T = ( BiTree ) malloc( sizeof( BiTNode ) );
 6         T->data = key;
 7         T->lchild = T->rchild = NULL;
 8         return true;
 9     }
10     else if ( T->data == key ) return false;
11     else if ( T->data > key ) return BSTInsert( T->lchild, key );
12     else return BSTInsert( T->rchild, key );
13 }

26.计算二叉树的带权路径长度(递归)

 1 int wpl = 0;
 2 int WPL_PreOrder( BiTree T, int deep )
 3 {
 4     if ( T == NULL ) return 0;
 5     if ( !T->lchild && !T->rchild )
 6         wpl += deep * T->weight;
 7     else
 8     {
 9         if ( T->lchild ) WPL_PreOrder( T->lchild, deep + 1 );
10         if ( T->rchild ) WPL_PreOrder( T->rchild, deep + 1 );
11     }
12     return wpl;
13 }

27.计算二叉树的带权路径长度(非递归)

 1 // 思路: 层序遍历的思想
 2 int wpl = 0;
 3 int WPL_LevelOrder( BiTree T )
 4 {
 5     if ( T == NULL ) return 0;
 6     BiTree Q[MAXSIZE], p;
 7     int front = -1, rear = -1, depth = 0, last = 0;
 8     Q[++rear] = T;
 9     while ( front != rear )
10     {
11         p = Q[++front];
12         if ( !p->lchild && !p->rchild )
13             wpl += depth * p->weight;
14         else
15         {
16             if ( p->lchild ) Q[++rear] = p->lchild;
17             if ( p->rchild ) Q[++rear] = p->rchild;
18         }
19         if ( front == last )
20         {
21             depth++; last = rear;
22         }
23     }
24     return wpl;
25 }

28.判断二叉树是否为二叉排序树

 1 ElemType preVal = MIN;
 2 bool IsBST( BiTree T )
 3 {
 4     if ( T == NULL ) return true;
 5     if ( !IsBST( T->lchild ) ) return false;
 6     if ( preVal >= T->data )
 7         return false;
 8     else
 9         preVal = T->data;
10     if ( !IsBST( T->rchild ) ) return false;
11     return true;
12 }

29.求出指定结点在二叉排序树中的层次

 1 int Level( BiTree T, BiTree p )
 2 {
 3     if ( T == NULL ) return 0;
 4     int n = 1;
 5     while ( T->data != p->data )
 6     {
 7         n++;
 8         if ( p->data < T->data )
 9             T = T->lchild;
10         else
11             T = T->rchild;
12     }
13     return n;
14 }

30.判断二叉树是否为平衡二叉树

 1 bool IsAVL( BiTree T, int& h )
 2 {
 3     int h1 = 0, h2 = 0;
 4     if (T==NULL )
 5     {
 6         h = 0; return true;
 7     }
 8     if ( IsAVL( T->lchild, h1 ) && IsAVL( T->rchild, h2 ) )
 9     {
10         if ( abs( h1 - h2 ) <= 1 )
11         {
12             h = 1 + ( h1 > h2 ? h1 : h2 );
13             return true;
14         }
15     }
16     return false;
17 }

31.从大到小输出二叉排序中所有值不小于k的关键字

 1 void DesOutput( BiTree T, ElemType k )
 2 {
 3     if ( T == NULL ) return;
 4     DesOutput( T->rchild, k );
 5     if ( T->data >= k )
 6         visit( T );
 7     else
 8         return;
 9     DesOutput( T->lchild, k );
10 }

32.在二叉排序树上查找第$k(1le kle n)$小的元素,要求平均时间复杂度为$O(log_{2}n)$二叉排序树上的每个结点中除data,lchild,rchild外,还增加一个count成员,保存以该结点为根的子树上的结点个数

 1 // 法一
 2 BiTree SearchSmallK( BiTree T, int k )
 3 {
 4     if ( k<1 || k>T->count ) return NULL;
 5     if ( T->lchild )
 6     {
 7         if ( k <= T->lchild->count )
 8             return SearchSmallK( T->lchild, k );
 9         else if ( k == T->lchild->count + 1 )
10             return T;
11         else
12             return SearchSmallK( T->rchild, k - ( T->lchild->count + 1 ) );
13     }
14     else
15     {
16         if ( k == 1 ) return T;
17         else return SearchSmallK( T->rchild, k - 1 );
18     }
19 }
 1 // 法二
 2 BiTree SearchSmallK( BiTree T, int k )
 3 {
 4     if ( k<1 || k>T->count ) return NULL;
 5     if ( T->lchild )
 6     {
 7         if ( k <= T->lchild->count )
 8             return SearchSmallK( T->lchild, k );
 9         else
10             k -= T->lchild->count;
11     }
12     if ( k == 1 ) return T;
13     if ( T->rchild )
14         return SearchSmallK( T->rchild, k - 1 );
15 }

33.对于含有$+,-,*,/$及括号的算术表达式(中缀表达式)写一个算法,将该表达式构造成相应的二叉树表示

 1 // 思想: 最后使用的操作符作为根.即:先+,-后*,/
 2 // 例如: a+b*(c-d)-e/f构造的表达式树如下:
 3 //                -
 4 //               /  
 5 //              +    /
 6 //             /   / 
 7 //            a  *  e  f
 8 //              / 
 9 //             b   -
10 //                / 
11 //               c   d
12 // 通过该表达式树,可以很容易得到:
13 // 前缀表达式: -+a*b-cd/ef
14 // 中缀表达式: a+b*c-d-e/f
15 // 后缀表达式: abcd-*+ef/-
16 BiTNode* BuildTree( char* exp, int s, int e )
17 {
18     if ( e - s == 1 )
19     {
20         BiTNode* p = ( BiTNode* ) malloc( sizeof( BiTNode ) );
21         p->data = exp[s];
22         p->lchild = p->rchild = NULL;
23         return p;
24     }
25     int c1 = -1, c2 = -1, c = 0, i;
26     for ( i = s; i < e; i++ )
27     {
28         if ( exp[i] == '(' ) c++;
29         else if ( ( exp[i] == '+' || exp[i] == '-' ) && !c )
30             c1 = i;
31         else if ( ( exp[i] == '*' || exp[i] == '/' ) && !c )
32             c2 = i;
33     }
34     if ( c1 < 0 ) c1 = c2;
35     if ( c1 < 0 ) return BuildTree( exp, s + 1, e - 1 );
36     BiTree* p = ( BiTNode* ) malloc( sizeof( BiTNode ) );
37     p->data = exp[c1];
38     p->lchild = BuildTree( exp, s, c1 );
39     p->rchild = BuildTree( exp, c1 + 1, e );
40     return p;
41 }
原文地址:https://www.cnblogs.com/brianyi/p/10179100.html