二叉数的一些题目(来自Standford cslibrary)

题目都是来自standford cs library:http://cslibrary.stanford.edu/110/BinaryTrees.html

是一个关于二叉树的专题,上面还有很多其他的专题,适合刚入门或者要找工作同学复习用。下面是我自己从二叉树这个专题当中选取的一些有代表性的题目。

基本数据结构如下:

struct node { 
    int data; 
    struct node* left; 
    struct node* right; 
} 

基本二叉树插入

Pointer Changing Code

There is a common problem with pointer intensive code: what if a function needs to change one of the pointer parameters passed to it? For example, the insert() function below may want to change the root pointer. In C and C++, one solution uses pointers-to-pointers (aka "reference parameters"). That's a fine technique, but here we will use the simpler technique that a function that wishes to change a pointer passed to it will  return  the new value of the pointer to the caller. The caller is responsible for using the new value. Suppose we have a change() function that may change the the root, then a call to change() will look like this...

// suppose the variable "root" points to the tree 
root = change(root);

We take the value returned by change(), and use it as the new value for root. This construct is a little awkward, but it avoids using reference parameters which confuse some C and C++ programmers, and Java does not have reference parameters at all. This allows us to focus on the recursion instead of the pointer mechanics. (For lots of problems that use reference parameters, see CSLibrary #105, Linked List Problems, http://cslibrary.stanford.edu/105/).

Insert()

Insert() -- given a binary search tree and a number, insert a new node with the given number into the tree in the correct place. The insert() code is similar to lookup(), but with the complication that it modifies the tree structure. As described above, insert() returns the new tree pointer to use to its caller. Calling insert() with the number 5 on this tree...

    2 
   / \ 
  1   10

returns the tree...

    2 
   / \ 
  1   10 
     / 
    5

The solution shown here introduces a newNode() helper function that builds a single node. The base-case/recursion structure is similar to the structure in lookup() -- each call checks for the NULL case, looks at the node at hand, and then recurs down the left or right subtree if needed.

/* 
 Helper function that allocates a new node 
 with the given data and NULL left and right 
 pointers. 
*/ 
struct node* NewNode(int data) { 
  struct node* node = new(struct node);    // "new" is like "malloc" 
  node->data = data; 
  node->left = NULL; 
  node->right = NULL;

  return(node); 
} 
 

/* 
 Give a binary search tree and a number, inserts a new node 
 with the given number in the correct place in the tree. 
 Returns the new root pointer which the caller should 
 then use (the standard trick to avoid using reference 
 parameters). 
*/ 
struct node* insert(struct node* node, int data) { 
  // 1. If the tree is empty, return a new, single node 
  if (node == NULL) { 
    return(newNode(data)); 
  } 
  else { 
    // 2. Otherwise, recur down the tree 
    if (data <= node->data) node->left = insert(node->left, data); 
    else node->right = insert(node->right, data);

    return(node); // return the (unchanged) node pointer 
  } 
} 

2. size()

This problem demonstrates simple binary tree traversal. Given a binary tree, count the number of nodes in the tree.

int size(struct node* node) {}

/* 
 Compute the number of nodes in a tree. 
*/ 
int size(struct node* node) { 
  if (node==NULL) { 
    return(0); 
  } else { 
    return(size(node->left) + 1 + size(node->right)); 
  } 
} 

7. hasPathSum()

We'll define a "root-to-leaf path" to be a sequence of nodes in a tree starting with the root node and proceeding downward to a leaf (a node with no children). We'll say that an empty tree contains no root-to-leaf paths. So for example, the following tree has exactly four root-to-leaf paths:

              5 
             / \ 
            4   8 
           /   / \ 
          11  13  4 
         /  \      \ 
        7    2      1

Root-to-leaf paths: 
   path 1: 5 4 11 7 
   path 2: 5 4 11 2 
   path 3: 5 8 13 
   path 4: 5 8 4 1

For this problem, we will be concerned with the sum of the values of such a path -- for example, the sum of the values on the 5-4-11-7 path is 5 + 4 + 11 + 7 = 27.

Given a binary tree and a sum, return true if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum. Return false if no such path can be found. (Thanks to Owen Astrachan for suggesting this problem.)

int hasPathSum(struct node* node, int sum)

/* 
 Given a tree and a sum, return true if there is a path from the root 
 down to a leaf, such that adding up all the values along the path 
 equals the given sum.
 Strategy: subtract the node value from the sum when recurring down, 
 and check to see if the sum is 0 when you run out of tree. 
*/ 
int hasPathSum(struct node* node, int sum) { 
  // return true if we run out of tree and sum==0 
  if (node == NULL) { 
    return(sum == 0); 
  } 
  else { 
  // otherwise check both subtrees 
    int subSum = sum - node->data; 
    return(hasPathSum(node->left, subSum) || 
           hasPathSum(node->right, subSum)); 
  } 
} 

8. printPaths()

Given a binary tree, print out all of its root-to-leaf paths as defined above. This problem is a little harder than it looks, since the "path so far" needs to be communicated between the recursive calls.  Hint:  In C, C++, and Java, probably the best solution is to create a recursive helper function printPathsRecur(node, int path[], int pathLen), where the path array communicates the sequence of nodes that led up to the current call. Alternately, the problem may be solved bottom-up, with each node returning its list of paths. This strategy works quite nicely in Lisp, since it can exploit the built in list and mapping primitives. (Thanks to Matthias Felleisen for suggesting this problem.)

Given a binary tree, print out all of its root-to-leaf paths, one per line.

void printPaths(struct node* node)

/* 
 Given a binary tree, print out all of its root-to-leaf 
 paths, one per line. Uses a recursive helper to do the work. 
*/ 
void printPaths(struct node* node) { 
  int path[1000];
  printPathsRecur(node, path, 0); 
}

/* 
 Recursive helper function -- given a node, and an array containing 
 the path from the root node up to but not including this node, 
 print out all the root-leaf paths. 
*/ 
void printPathsRecur(struct node* node, int path[], int pathLen) { 
  if (node==NULL) return;

  // append this node to the path array 
  path[pathLen] = node->data; 
  pathLen++;

  // it's a leaf, so print the path that led to here 
  if (node->left==NULL && node->right==NULL) { 
    printArray(path, pathLen); 
  } 
  else { 
  // otherwise try both subtrees 
    printPathsRecur(node->left, path, pathLen); 
    printPathsRecur(node->right, path, pathLen); 
  } 
}

// Utility that prints out an array on a line. 
void printArray(int ints[], int len) { 
  int i; 
  for (i=0; i<len; i++) { 
    printf("%d ", ints[i]); 
  } 
  printf("\n"); 
} 

9. mirror()

Change a tree so that the roles of the left and right pointers are swapped at every node.

 So the tree... 
       4 
      / \ 
     2   5 
    / \ 
   1   3

 is changed to... 
       4 
      / \ 
     5   2 
        / \ 
       3   1

The solution is short, but very recursive. As it happens, this can be accomplished without changing the root node pointer, so the return-the-new-root construct is not necessary. Alternately, if you do not want to change the tree nodes, you may construct and return a new mirror tree based on the original tree.

void mirror(struct node* node)

/* 
 Change a tree so that the roles of the 
 left and right pointers are swapped at every node.
 So the tree... 
       4 
      / \ 
     2   5 
    / \ 
   1   3

 is changed to... 
       4 
      / \ 
     5   2 
        / \ 
       3   1 
*/ 
void mirror(struct node* node) { 
  if (node==NULL) { 
    return; 
  } 
  else { 
    struct node* temp;

    // do the subtrees 
    mirror(node->left); 
    mirror(node->right);

    // swap the pointers in this node 
    temp = node->left; 
    node->left = node->right; 
    node->right = temp; 
  } 
} 

11. sameTree()

Given two binary trees, return true if they are structurally identical -- they are made of nodes with the same values arranged in the same way. (Thanks to Julie Zelenski for suggesting this problem.)

int sameTree(struct node* a, struct node* b) 

/* 
 Given two trees, return true if they are 
 structurally identical. 
*/ 
int sameTree(struct node* a, struct node* b) { 
  // 1. both empty -> true 
  if (a==NULL && b==NULL) return(true);
  // 2. both non-empty -> compare them 
  else if (a!=NULL && b!=NULL) { 
    return( 
      a->data == b->data && 
      sameTree(a->left, b->left) && 
      sameTree(a->right, b->right) 
    ); 
  } 
  // 3. one empty, one not -> false 
  else return(false); 
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值