星海's Blog

老头初学编程

算法导论 动态顺序统计树练习题 14.1-3 14.1-4 14.1-5

 *
 *    Description:  算法导论 第14章 动态顺序统计树练习题解答(伪代码)
 *
 *        Version:  1.0
 *        Created:  2012年11月19日 22时59分16秒
 *         Author:  sd44
 *   Organization:  
 *
 * =====================================================================================
 */

// 14.1-3 OS-SELECT的非递归

OS-SELECT(ptr x, int i) {
  if (i > x->size)
    return NULL;
  int r;
  ptr tmp = x;
  while (1) {
    r = tmp->left->size + 1;
    if (i < r) {
      tmp = tmp->left;
    } else if (i > r) {
      i = i - r;
      tmp = tmp->right;
    }
    else
      return r;
  }
}

// 14.1-4 OS-KEY-RANK(T, k) 较为简单,稍微修改树的find(元素)操作即可,
// 题目要求为递归形式,我实现的是非递归形式。
// 解答:
//
 r为动态集合中k的秩。。

 r初始化为0.
 如果k比当前节点的元素值大,则向右子节点移动,并记录当前节点左子结点的size且
 +1。r += currentNode->left->size + 1;
 如果k比当前节点的元素值小,则向左子结点移动,不对r进行加减操作。
 如果k等于当前节点的元素时,r += currentNode->left->size + 1;


//14.1-5 如何在O(lg N)的时间内,确定x在树的线性序中第i个后继。
//解答:
//
首先,find找到x在顺序统计树中的节点node。
如果node右节点的size大于i,则进入右结点,node = node->right,递归找第i个后继

如果node右结点的size小于i,则i = i - node->right->size,此时分两种情况:
1, 如果node为其父的右结点,则上移,node = node->parent

2, 如果node为其父的左节点,则上移,node = node->parent,i = i - 1。如果i == 1,返回此时的node(为原来node的parent)。
 否则递归找第i个后继

算法导论思考题 13-4 Treap

struct treap {
   type element;
   int priority ;

}

treap array[n]; //由用户构建一个带有元素与互异优先级的数组。

for (int i = 0; i < n; i++) {
   treePtr = treapTreeInsert(array[i].elemnt)  //执行普通的二叉树插入,保存插入后的节点
   while (treePtr != treepHeader && treePtr->priority < treePtr->parent->priority) {
     // treePtr不为树根,且优先级比其父节点小。
      if (treePtr = treePtr->parent->left)
        rightRorate(treePtr->parent);
      else
        leftRorate(treePtr->parent);


未经验证,有过有错,请指正评论或给我发EMAIL

算法导论 红黑树的实现代码(C++)

代码结构参照了Mark Allen Weiss的《数据结构与算法分析 C++语言描述》中的模板结构。

代码根据《算法导论》中的伪代码而来。

在gtalk群与FXY兄说起红黑树,他介绍了一个非常牛B的算法网址--结构之法:

http://blog.csdn.net/v_july_v/article/details/6543438

 

http://blog.csdn.net/v_JULY_v/article/details/6284050

根据以上网址的图解,验证并DEBUG了自己的代码(早期代码有错误的地方)

 

DeleteFixup和InsertFixup中的颜色修改,维持红黑树性质的代码不是很清晰。。。。

 

/*
 * =====================================================================================
 *
 *       Filename:  redblacktree.h
 *
 *    Description:  红黑树的实现:
 *    红黑树确保没有一条路径会比其他路径长出两倍,接近平衡。
 *
 *    红黑树的5个基本性质:
 *    1,每个节点为红或黑
 *    2,根节点为黑
 *    3,每个叶结点(nullNode)为黑
 *    4,如果一个节点是红的,那他的两个儿子都是黑的
 *    5,对每个节点,从该结点到其子孙节点的所有路径上包含相同数目的黑节点
 *
 *        Version:  1.0
 *        Created:  2012年11月16日 17时47分03秒
 *         Author:  sd44 (sd44sd44@yeah.net), 
 *
 * =====================================================================================
 */

#ifndef  redblacktree_INC
#define  redblacktree_INC

#include <iostream>

template <typename Comparable>
class RedBlackTree
{
  // 调用以下返回RedBlackNode *类型的函数时,注意要检查值是不是nullNode,再进行操作。
 public:
  enum TreeColor {RED, BLACK};
  struct RedBlackNode {
    Comparable element;
    RedBlackNode *parent;
    RedBlackNode *left;
    RedBlackNode *right;
    TreeColor color;
    RedBlackNode( const Comparable & theElement = Comparable( ), RedBlackNode *par = NULL,
                  RedBlackNode *lt = NULL, RedBlackNode *rt = NULL,
                  TreeColor defaultColor = RED )
      : element( theElement ), parent(par), left( lt ), right( rt ), color(defaultColor)
    { }
  };

  // 显示构造函数,传入一个可以< >比较的元素
  explicit RedBlackTree() {
    nullNode = new RedBlackNode;
    // nullNode的初始化未必有必要吧?
    nullNode->parent = nullNode->left = nullNode->right = nullNode;
    nullNode->color = BLACK;
    header = nullNode;
  }

  ~RedBlackTree() {
    makeEmpty();
    delete nullNode;
  }

  const Comparable &findMin() {
    return findMinPos(header)->element;
  }
  const Comparable &findMax() {
    return findMaxPos(header)->element;
  }

  RedBlackNode *treeHeader() { return header; }
  RedBlackNode *treeNullNode() { return nullNode; }

  RedBlackNode *find(RedBlackNode *pos, const Comparable &element) const;
  RedBlackNode *findSuccessor(RedBlackNode *pos);
  bool isEmpty() const;
  void printTree() const { printTree(header); }
  void printTree(RedBlackNode *pos) const;
  void makeEmpty();
  void rbInsert(const Comparable &x);
  void rbDelete(const Comparable &x);
  RedBlackNode *rbDelete(RedBlackNode *node);

  void leftChildDeleteFixup(RedBlackTree::RedBlackNode * &node);
  void rightChildDeleteFixup(RedBlackTree::RedBlackNode * &node);
private:

  RedBlackNode *findMinPos(RedBlackNode *pos) const;
  RedBlackNode *findMaxPos(RedBlackNode *pos) const;
  void rbInsertFixup(RedBlackNode *node);
  void rbDeleteFixup(RedBlackNode *node);
  void leftRotate(RedBlackNode *x);
  void rightRotate(RedBlackNode *x);
  void emptySubTree(RedBlackNode *pos);

  RedBlackNode *header;
  RedBlackNode *nullNode;

};
#endif   /* ----- #ifndef redblacktree_INC  ----- */

 

#include "redblacktree.h"
#include <cstdlib>
#include <ctime>

template <typename Comparable>
typename RedBlackTree<Comparable>::RedBlackNode *RedBlackTree<Comparable>::findMinPos(RedBlackNode *pos) const
{
  if (pos == nullNode)
    return pos;
  while (pos->left != nullNode)
    pos = pos->left;
  return pos;
}

template <typename Comparable>
typename RedBlackTree<Comparable>::RedBlackNode
*RedBlackTree<Comparable>::findMaxPos(RedBlackNode *pos) const
{
  if (pos == NULL)
    return pos;
  // 此处用的是nullNode,而非NULL,也是红黑树与普通二叉树的NULL区别.
  while (pos->left != nullNode)
    pos = pos->left;
  return pos;
}

template <typename Comparable>
typename RedBlackTree<Comparable>::RedBlackNode
*RedBlackTree<Comparable>::find(
    RedBlackTree<Comparable>::RedBlackNode *pos, const Comparable &element) const
{
  if (pos == NULL)
    return pos;
  while (pos != nullNode && pos->element != element) {
      if (pos->element < element)
        pos = pos->right;
      else if (pos ->element > element)
        pos = pos->left;
    }
  return pos;
}

template <typename Comparable>
typename RedBlackTree<Comparable>::RedBlackNode
*RedBlackTree<Comparable>::findSuccessor(RedBlackTree::RedBlackNode *pos)
{
  if (pos->right != nullNode)
    return findMinPos(pos->right);
  RedBlackNode *successor = pos->parent;
  while (successor != nullNode && pos == successor->right) {
      pos = successor;
      successor = pos->parent;
    }
  return successor;
}

template <typename Comparable>
bool RedBlackTree<Comparable>::isEmpty() const
{
  return treeHeader() == nullNode;
}

template <typename Comparable>
void RedBlackTree<Comparable>::printTree(RedBlackNode *pos) const
{
  if (pos == NULL || pos == nullNode)
    return;
  if (pos->left != nullNode)
    printTree(pos->left);
  //WARNING: 此处cout只适用于可以打印的元素,请参照自己的数据结构实现
  std::cout << pos->element;
  if (pos->color == BLACK)
    std::cout << ":BLACK";
  else
    std::cout << ":RED";
  std::cout << "\t";
  if (pos->right != nullNode)
    printTree(pos->right);
}

template <typename Comparable>
void RedBlackTree<Comparable>::makeEmpty()
{
  emptySubTree(header);
  header = nullNode;
}

template <typename Comparable>
void RedBlackTree<Comparable>::emptySubTree(RedBlackNode *pos) {
  if (pos == nullNode)
    return;
  emptySubTree(pos->left);
  emptySubTree(pos->right);
  delete pos;
}

template <typename Comparable>
void RedBlackTree<Comparable>::rbInsert(const Comparable &x)
{
  RedBlackNode *preFindPos = nullNode;
  RedBlackNode *findPos = header;

  while (findPos != nullNode) {
      preFindPos = findPos;
      if (findPos->element > x)
        findPos = findPos->left;
      else
        findPos = findPos->right;
    }

  // 新节点元素为x,默认为红色,父节点为preFindPos,其他为nullNode。
  RedBlackNode *newNode = new RedBlackNode(x, preFindPos, nullNode, nullNode, RED);
  newNode->element = x;
  newNode->parent = preFindPos;
  if (preFindPos == nullNode)
    header = newNode;
  else if (x < preFindPos->element)
    preFindPos->left = newNode;
  else
    preFindPos->right = newNode;

  rbInsertFixup(newNode);
}

template <typename Comparable>
void RedBlackTree<Comparable>::rbInsertFixup(RedBlackTree::RedBlackNode *node)
{
  RedBlackNode *uncle;
  while (node->parent->color == RED) {
      //以下六种情况前提均是,父节点为红,爷结点为黑

      // 如果新插入结点node,执行以下操作:
      // 因为根节点为黑色,根节点的子节点不执行此条语句,所以node的爷爷结点肯定不是nullNode。
      // 访问不会越界。
      if (node->parent == node->parent->parent->left) {
          uncle = node->parent->parent->right;
          if (uncle->color == RED) { // 第一种情况:node与其父结点,叔父结点均为RED
              // 此时违反性质4:红节点的两个子节点均为黑,于是:
              // 将 父、叔结点改为黑,
              // 爷爷结点改为红,以维持性质五:黑高度相同。
              node->parent->color = BLACK;
              uncle->color = BLACK;
              node->parent->parent->color = RED;
              // node上移两层,迭代考察前爷爷结点为红是否违反性质4
              node = node->parent->parent;
            } else  {  // 叔父结点为黑色,父节点为红的情况。
              if (node == node->parent->right) {
                  //第二种情况:node父节点为左节点,node为右结点
                  node = node->parent;
                  // 左旋,将情况改为第三种情况
                  leftRotate(node);
                }
              // 第三种情况:node父节点为左节点,node为左节点。
              node->parent->color = BLACK; //uncle为黑,node为左红节点时的情况
              node->parent->parent->color = RED;
              rightRotate(node->parent->parent);
            }
        } else {
          //else 语句执行 node的父节点为右节点时的情况。
          uncle = node->parent->parent->left;
          if (uncle->color == RED) { // 第四种情况:父节点为右结点,node与其父,叔父结点均为RED
              // 此时违反性质4:红节点的两个子节点均为黑,于是:
              // 将 父、叔结点改为黑,
              // 爷爷结点改为红,以维持性质五:黑高度相同。
              node->parent->color = BLACK;
              uncle->color = BLACK;
              node->parent->parent->color = RED;
              // node上移两层,迭代考察前爷爷结点为红是否违反性质4
              node = node->parent->parent;
            } else  {  // 父节点为红,叔结点为黑色的情况。
              if (node == node->parent->left) {
                  // 第五种情况 父节点为右结点,node为左节点,叔结点为黑。
                  node = node->parent;
                  // 右旋,将情况改为
                  rightRotate(node);
                }
              // 第六种情况 父节点为右结点,node为右节点,叔结点为黑。
              node->parent->color = BLACK; //uncle为黑,node为左红节点时的情况
              node->parent->parent->color = RED;
              leftRotate(node->parent->parent);
            }
        }
    }
  header->color = BLACK;
}

template <typename Comparable>
void RedBlackTree<Comparable>::rbDelete(const Comparable &x)
{
  RedBlackNode *ptr = find(header, x);
  if (ptr != nullNode){
    RedBlackNode *delNode = rbDelete(ptr);
    if (delNode != nullNode)
      delete delNode;
  }
}

template <typename Comparable>
typename RedBlackTree<Comparable>::RedBlackNode *
RedBlackTree<Comparable>::rbDelete(RedBlackTree::RedBlackNode *node)
{
  RedBlackNode *delNode;
  if (node->left == nullNode || node->right == nullNode)
    delNode = node;
  else
    delNode = findSuccessor(node);

  RedBlackNode *delNodeChild;
  // 以下if...else...语句要结合上边来看
  // 如果node左右子女有一个为nullNode,则下面语句找到要提升的delNodeChild。
  // 如果某节点有两个子女,则其后继没有左子女。此时如果delNode = findSuccessor的话,
  // delNode->left一定等于nullNode,肯定会执行delNodeChild = delNode->right。

  if (delNode->left != nullNode)
    delNodeChild = delNode->left;
  else
    delNodeChild = delNode->right;

  delNodeChild->parent = delNode->parent;
  if (delNode->parent == nullNode)
    header = delNodeChild;
  else if (delNode == delNode->parent->left)
    delNode->parent->left = delNodeChild;
  else
    delNode->parent->right = delNodeChild;

  if (delNode != node)
    node->element = delNode->element;

  // 如果delNode->color为红的话,则红黑性质得以保持。
  // 因为此时delNode肯定不为根,根节点仍为黑
  // delNode的父节点肯定为黑,被提升的delNodeChild不会与之违反性质:红节点的子节点不能有红
  // 黑高度没有变化

  if (delNode->color == BLACK)
    rbDeleteFixup(delNodeChild);

  // WARNNING:此处没有delete delNode,用户需要接收此函数返回值然后delete
  // 或者在此处delete,且将函数返回类型设置为void。
  return delNode;
}

template <typename Comparable>
void RedBlackTree<Comparable>::rbDeleteFixup(RedBlackTree::RedBlackNode *node)
{
  // 此时node->color因为父亲黑节点的删除,将其视为具有双重颜色特性,为黑黑或者红黑,要调整
  while (node != header && node->color == BLACK) {
      // while循环处理node->color为黑且不为header的情况,此时node为黑黑的双重黑特性。
      if (node == node->parent->left)
        leftChildDeleteFixup(node);
      else
        rightChildDeleteFixup(node);
    }

  // 如果node->color为红或者为header的话,此时只需简单的将其设置为BLACK即可,见此:
  node->color =BLACK;
}

template <typename Comparable>
void RedBlackTree<Comparable>::leftChildDeleteFixup(RedBlackTree::RedBlackNode * &node)
{
  //node为双重黑特性。
  RedBlackNode *rightNode = node->parent->right;
  // case 1: rightNode为红,两个子节点为黑,将其转换为以下case
  if (rightNode->color == RED) {
      rightNode->color = BLACK;
      node->parent->color = RED;
      leftRotate(node->parent);
      // node的右子节点为旋转之前rightNode的左黑孩子,继续进入下面的case以维持红黑树性质
      rightNode = node->parent->right;
    }

  // case 2: rightNode与其两个子节点均为黑。
  if (rightNode->left->color == BLACK && rightNode->right->color == BLACK) {
      rightNode->color = RED;
      //简单将rightNode改为黑即可维持黑高度特性,node的双重特性取消,为单色。
      // 此时将node设为其父,考察其父的红黑性质。
      node = node->parent;
    } else {
      // case 3:rightNode与其右孩子为黑,左孩子为红,将其旋转后进入case 4
      if (rightNode->right->color== BLACK) {
          rightNode->left->color = BLACK;
          rightNode->color = RED;
          rightRotate(rightNode);
          rightNode = node->parent->right;
        }
      // case 4:rightnode为黑,其右孩子为红

      //rightNode颜色为其父颜色,旋转后以维持原来的黑高度
      rightNode->color = node->parent->color;

      // TODO:此时意义不明。。。node->parent此时一定为红色吗?
      node->parent->color= BLACK;
      rightNode->right->color = BLACK;
      leftRotate(node->parent);
      node = header;
    }
}

template <typename Comparable>
void RedBlackTree<Comparable>::rightChildDeleteFixup(RedBlackTree::RedBlackNode *&node)
{
  //node为双重黑特性。
  RedBlackNode *leftNode = node->parent->left;
  // case 1: rightNode为红,两个子节点为黑,将其转换为以下case
  if (leftNode->color == RED) {
      leftNode->color = BLACK;
      node->parent->color = RED;
      rightRotate(node->parent);
      // node的左子节点为旋转之前leftNode的右黑孩子,继续进入下面的case以维持红黑树性质
      leftNode = node->parent->left;
    }

  // case 2: lefttNode与其两个子节点均为黑。
  if (leftNode->left->color == BLACK && leftNode->right->color == BLACK) {
      leftNode->color = RED;
      //简单将lefttNode改为黑即可维持黑高度特性,node的双重特性取消,为单色。
      // 此时将node设为其父,考察其父的红黑性质。
      node = node->parent;
    } else {
      // case 3:leftNode与其左孩子为黑,右孩子为红,将其旋转后进入case 4
      if (leftNode->left->color== BLACK) {
          leftNode->right->color = BLACK;
          leftNode->color = RED;
          leftRotate(leftNode);
          leftNode = node->parent->left;
        }
      // case 4:leftNode为黑,其左孩子为红

      //leftNode颜色为其父颜色,旋转后以维持原来的黑高度
      leftNode->color = node->parent->color;

      // TODO:此时意义不明。。。node->parent此时一定为红色吗?
      node->parent->color= BLACK;
      leftNode->left->color = BLACK;
      rightRotate(node->parent);
      node = header;
    }
}

// 当在结点X上做左旋时,我们假设他的右孩子不是nullNode,
// x可以为任意右孩子不是nullNode的结点。

//左旋时,所影响到的结点,只有x,x的右孩子,与x右孩子的左节点。
template <typename Comparable>
void RedBlackTree<Comparable>::leftRotate(RedBlackTree::RedBlackNode *x)
{
  RedBlackNode *y = x->right;
  x->right = y->left;  // 旋转中,x的右结点设为y的左结点
  if (y->left != nullNode)
    y->left->parent = x;
  y->parent= x->parent;
  if (x->parent == nullNode) {
      header = y;
    } else if (x == x->parent->left)
    x->parent->left = y;
  else
    x->parent->right = y;
  y->left = x;
  x->parent = y;
}

//左旋时,所影响到的结点,只有x,x的左孩子,与x左孩子的右节点。
template <typename Comparable>
void RedBlackTree<Comparable>::rightRotate(RedBlackTree::RedBlackNode *x)
{
  RedBlackNode *y = x->left;
  x->left = y->right;
  if (y->right != nullNode)
    y->right->parent = x;
  y->parent = x->parent;
  if (x->parent == nullNode)
    header = y;
  else if ( x == x->parent->left)
    x->parent->left = y;
  else
    x->parent->right = y;
  y->right = x;
  x->parent = y;
}

int main(int argc, char *argv[])
{
  RedBlackTree<int> tmp;
  srand(unsigned(time(NULL)));
  for (int i = 0; i < 20; i++)
    tmp.rbInsert(rand() % 10000);

  tmp.printTree();
  std::cout << std::endl;
  std::cout << std::endl;

  tmp.makeEmpty();
  tmp.rbInsert(12);
  tmp.rbInsert(1);
  tmp.rbInsert(9);
  tmp.rbInsert(2);
  tmp.rbInsert(0);
  tmp.rbInsert(11);
  tmp.rbInsert(7);
  tmp.rbInsert(19);
  tmp.rbInsert(4);
  tmp.rbInsert(15);
  tmp.rbInsert(18);
  tmp.rbInsert(5);
  tmp.rbInsert(14);
  tmp.rbInsert(13);
  tmp.rbInsert(10);
  tmp.rbInsert(16);
  tmp.rbInsert(6);
  tmp.rbInsert(3);
  tmp.rbInsert(8);
  tmp.rbInsert(17);
  tmp.printTree();

  std::cout << std::endl << std::endl;
  tmp.rbDelete(12);
  tmp.rbDelete(1);
  tmp.rbDelete(9);
  tmp.rbDelete(2);
  tmp.rbDelete(0);
  tmp.printTree();

  return 0;
}

二叉树的C++模板,摘自Mark Alen Weiss,中序用栈遍历摘自microgoogle

Mark Alen Weiss:
http://users.cis.fiu.edu/~weiss/#dsaac++3
《数据结构与算法分析 C++语言描述》

提供了较好的C++样式和代码风格,用到了模板,重载和指针引用,值得学习。。

但在效率上稍差一点,另外没有parent节点。

 

MicroGoogle:

http://www.cnblogs.com/shuaiwhu/archive/2011/04/20/2065055.html

非递归遍历用栈版本和不用栈版本。

我这里只参照micogoogle的实现了栈版本中序递归(基本全是照抄),非递归版本暂不考虑。

#ifndef BINARY_SEARCH_TREE_H
#define BINARY_SEARCH_TREE_H

// #include "dsexceptions.h"
#include <iostream>    // For NULL
#include <vector>
using namespace std;

// BinarySearchTree class
//
// CONSTRUCTION: with ITEM_NOT_FOUND object used to signal failed finds
//
// ******************PUBLIC OPERATIONS*********************
// void insert( x )       --> Insert x
// void remove( x )       --> Remove x
// bool contains( x )     --> Return true if x is present
// Comparable findMin( )  --> Return smallest item
// Comparable findMax( )  --> Return largest item
// boolean isEmpty( )     --> Return true if empty; else false
// void makeEmpty( )      --> Remove all items
// void printTree( )      --> Print tree in sorted order
// ******************ERRORS********************************
// Throws UnderflowException as warranted

template <typename Comparable>
class BinarySearchTree
{
public:
  BinarySearchTree( ) : root( NULL ) {
  }

  BinarySearchTree( const BinarySearchTree & rhs ) : root( NULL ) {
    *this = rhs;
  }

  /**
   * Destructor for the tree
   */
  ~BinarySearchTree( ) {
    makeEmpty( );
  }

  /**
   * Find the smallest item in the tree.
   * Throw UnderflowException if empty.
   */
  const Comparable & findMin( ) const {
    if ( isEmpty( ) ) {
      //      throw UnderflowException( );
      ;
    }
    return findMin( root )->element;
  }

  /**
   * Find the largest item in the tree.
   * Throw UnderflowException if empty.
   */
  const Comparable & findMax( ) const {
    if ( isEmpty( ) ) {
      //      throw UnderflowException( );
      ;
    }
    return findMax( root )->element;
  }

  /**
   * Returns true if x is found in the tree.
   */
  bool contains( const Comparable & x ) const {
    return contains( x, root );
  }

  /**
   * Test if the tree is logically empty.
   * Return true if empty, false otherwise.
   */
  bool isEmpty( ) const {
    return root == NULL;
  }

  /**
   * Print the tree contents in sorted order.
   */
  void printTree( ostream & out = cout ) const {
    if ( isEmpty( ) ) {
      out << "Empty tree" << endl;
    } else {
      printTree( root, out );
    }
  }

  /**
   * Make the tree logically empty.
   */
  void makeEmpty( ) {
    makeEmpty( root );
  }

  /**
   * Insert x into the tree; duplicates are ignored.
   */
  void insert( const Comparable & x ) {
    insert( x, root );
  }

  /**
   * Remove x from the tree. Nothing is done if x is not found.
   */
  void remove( const Comparable & x ) {
    remove( x, root );
  }

  /**
   * Deep copy.
   */
  const BinarySearchTree & operator=( const BinarySearchTree & rhs ) {
    if ( this != &rhs ) {
      makeEmpty( );
      root = clone( rhs.root );
    }
    return *this;
  }

private:
  struct BinaryNode {
    Comparable element;
    BinaryNode *left;
    BinaryNode *right;

    BinaryNode( const Comparable & theElement, BinaryNode *lt, BinaryNode *rt )
      : element( theElement ), left( lt ), right( rt ) { }
  };

  BinaryNode *root;


  /**
   * Internal method to insert into a subtree.
   * x is the item to insert.
   * t is the node that roots the subtree.
   * Set the new root of the subtree.
   */
  void insert( const Comparable & x, BinaryNode * & t ) {
    if ( t == NULL ) {
      t = new BinaryNode( x, NULL, NULL );
    } else if ( x < t->element ) {
      insert( x, t->left );
    } else if ( t->element < x ) {
      insert( x, t->right );
    } else {
//      ;  // Duplicate; do nothing
    }
  }

  /**
   * Internal method to remove from a subtree.
   * x is the item to remove.
   * t is the node that roots the subtree.
   * Set the new root of the subtree.
   */
  void remove( const Comparable & x, BinaryNode * & t ) {
    if ( t == NULL ) {
      return;  // Item not found; do nothing
    }
    if ( x < t->element ) {
      remove( x, t->left );
    } else if ( t->element < x ) {
      remove( x, t->right );
    } else if ( t->left != NULL && t->right != NULL ) { // Two children
      t->element = findMin( t->right )->element;
      remove( t->element, t->right );
    } else {
      BinaryNode *oldNode = t;
      t = ( t->left != NULL ) ? t->left : t->right;
      delete oldNode;
    }
  }

  /**
   * Internal method to find the smallest item in a subtree t.
   * Return node containing the smallest item.
   */
  BinaryNode * findMin( BinaryNode *t ) const {
    if ( t == NULL ) {
      return NULL;
    }
    if ( t->left == NULL ) {
      return t;
    }
    return findMin( t->left );
  }

  /**
   * Internal method to find the largest item in a subtree t.
   * Return node containing the largest item.
   */
  BinaryNode * findMax( BinaryNode *t ) const {

    if ( t != NULL )
      while ( t->right != NULL ) {
        t = t->right;
      }
    return t;
  }


  /**
   * Internal method to test if an item is in a subtree.
   * x is item to search for.
   * t is the node that roots the subtree.
   */
  bool contains( const Comparable & x, BinaryNode *t ) const {
    if ( t == NULL ) {
      return false;
    } else if ( x < t->element ) {
      return contains( x, t->left );
    } else if ( t->element < x ) {
      return contains( x, t->right );
    } else {
      return true;  // Match
    }
  }
  /****** NONRECURSIVE VERSION*************************
    bool contains( const Comparable & x, BinaryNode *t ) const
    {
    while( t != NULL )
    if( x < t->element )
    t = t->left;
    else if( t->element < x )
    t = t->right;
    else
    return true;    // Match

    return false;   // No match
    }
   *****************************************************/

  /**
   * Internal method to make subtree empty.
   */
  void makeEmpty( BinaryNode * & t ) {
    if ( t != NULL ) {
      makeEmpty( t->left );
      makeEmpty( t->right );
      delete t;
    }
    t = NULL;
  }

  //
  //  void printTree( BinaryNode *t, ostream & out ) const {
  //    if ( t != NULL ) {
  //      printTree( t->left, out );
  //      out << t->element << endl;
  //      printTree( t->right, out );
  //    }
  //  }

  void printTree( BinaryNode *t, ostream &out) const {
//  将vector当作栈来实现,push_back,pop_back,back
    vector<BinaryNode *> stackList;
    while (t != NULL || !stackList.empty()) {
      while (t != NULL) {
        stackList.push_back(t);
        t = t->left;
      }
      t = stackList.back();
      stackList.pop_back();
      out << t->element << "\t";
      t = t->right;
    }
  }

    /**
     * Internal method to clone subtree.
     */
    BinaryNode * clone( BinaryNode *t ) const {
      if ( t == NUL
          return NULL;
          } else {
          return new BinaryNode( t->element, clone( t->left ), clone( t->right ) );
          }
          }
          };

#endif

算法导论习题 12-2

实现比较简单。

 

只需在二叉树节点内加入一个bool hasdata成员,表示此节点包含有效位串。

在插入时,遍历位串每一位,如果为1,则二叉树向右,如为0,则向左,在遍历位完成时,设置当前节点hasdata值为true。

 

最后的中序遍历更为简单

普通中序遍历原型为 middleOrder(currentNode)

代码为

判断 NODE不为NULL;

midlleOrder(currentNode->left);

printKey(currentNode);

middleOrder(currentNode->right);

 

基数树只需要加个形参即可。

原型 middleOrder(currentNode, string pre = string())

代码:

判断NODE不为NULL

   middleOrder(currentNode->left, pre +"0");

  if (currentNode->hasData)

      print(string);

  middleOrder(currentNode->right, pre +"1");

 

调用:

middleOrder(Tree)

算法导论9.1-1 用O(N + lgn -2 )的运行时间找出第二小元素

代码有点混乱,C/C++不分,主要集中在createtree的 int &size形参上,其实最好是建个类存储当前层的SIZE,或者其他办法。因时间问题,不再更改。

 

#include <iostream>
/*
 * ===  FUNCTION  ======================================================================
 *         Name:  findSecond
 *  Description:  算法导论练习 9.1-1
 *  证明:在最坏情况下,利用n + lgn -2次比较,,即可找到n个元素中的第2个小元素
 *  (提示:同时找最小元素)
 *  限制:需要支持随机迭代
 *  思路:起先想到用分治算法,但设计不出,还是忍不住看了算法导论的答案:
 *
 * To find the smallest element construct a tournament as follows:
 * Compare all the numbers in pairs.
 * Only the smallest number of each pair is potentially the
 smallest of all so the problem is reduced to size n/2 .
 * Continuing in this fashion until there is only one left clearly solves the problem.
 * Exactly n − 1 comparisons are needed since the tournament can be drawn as an n-leaf binary
tree
  which has n − 1 internal nodes (show by induction on n).
 * Each of these nodes correspond to a comparison.
 * We can use this binary tree to also locate the second
 * smallest number. The path from the root to the smallest element
 * (of height lg n ) must contain the second smallest element. Conducting
 * a tournament among these uses lg n − 1 comparisons.
 * The total number of comparisons are: n − 1 + lg n − 1 = n + lg n − 2.
 * =====================================================================================
 */

bool compInt(const int &a, const int &b)
{
  return a < b;
}

template <typename T>
class findSecondNode {
public:
  findSecondNode() : element(0), compareElement(0), child(0) { }
  findSecondNode(const T *elementArg, const T *compareElementArg, const findSecondNode<T> *childArg)
    : element(elementArg), compareElement(compareElementArg), child(childArg) { }
  const T *element;          /* 本元素指针 */
  const T *compareElement;   /* 与本元素比较的元素指针 */
  const findSecondNode<T> *child;            /* 二叉树子节点,与本元素同值 */
};

template <typename T, typename compFunc>
const findSecondNode<T> *createTree(const findSecondNode<T> *array, int &size, compFunc func);

template <typename T, typename compFunc>
const T *findSecond(T *array, int size, compFunc func);

 

 

#include <iostream>
#include <vector>
#include "find2nd.h"

// 如果失败,返回0值。
template <typename T, typename compFunc>
const findSecondNode<T> *createTree(const findSecondNode<T> *array, int &size,
compFunc func)
{
  if (size <= 0) {
    size = 0;
    return static_cast<findSecondNode<T> *>(0);
    }
  if (size == 1){
    size = 0;
    return array;
    }

  bool isEvenSize;
  int rowSize;
  if ((size % 2) != 0) {
    isEvenSize = false;
    rowSize = size / 2 + 1;
  } else {
    isEvenSize = true;
    rowSize = size / 2;
  }

  findSecondNode<T> *row = new findSecondNode<T>[rowSize];
  int i;
  for (i = 0; i < size -1; i += 2)
    if (func(*(array[i].element), *(array[i + 1].element))) {
      row[i / 2] = findSecondNode<T>(array[i].element, array[i + 1].element, array + i);
    } else {
      row[i / 2] = findSecondNode<T>(array[i + 1].element, array[i].element, array
+ i + 1);
    }

  if (!isEvenSize) {
    row[rowSize - 1] = findSecondNode<T>(array[i].element,
static_cast<T *>(0), array +
i - 1);
  }
  size = rowSize;
  return row;
}

template <typename T, typename compFunc>
const T *findSecond( T *array, int size, compFunc func)
{
  if (size <= 1)
    return 0;
  if (size == 2)
    return func(array[0], array[1]) ? array : array + 1;
  findSecondNode<T> *row;

  bool evenNumSize;
  int rowSize;
  if ((size % 2) != 0) {
    evenNumSize = false;
    rowSize = size / 2 + 1;
  } else {
    evenNumSize = true;
    rowSize = size / 2;
  }

  row = new findSecondNode<T>[rowSize];

  int i;
  for (i = 0; i < size -1; i += 2)
    if (func(array[i], array[i + 1])) {
      row[i / 2] = findSecondNode<T>(array + i, array +i + 1,
static_cast<findSecondNode<T> *>(0));
    } else {
      row[i / 2] = findSecondNode<T>(array + i + 1, array + i,
static_cast<findSecondNode<T> *>(0));
    }

  if (!evenNumSize)
    row[rowSize -1] = findSecondNode<T>(array + i, static_cast<T *>(0),
static_cast<findSecondNode<T> *>(0));

  std::vector<const findSecondNode<T> *> destructor;
  destructor.push_back(row);
  const findSecondNode<T> *ptr = row;

  while ((ptr = createTree(ptr, rowSize, func)) !=
         static_cast<const findSecondNode<T> *>(0))
      destructor.push_back(ptr);
  destructor.pop_back();
  ptr = destructor.at(destructor.size() - 1);
  const T *maySecond = ptr->compareElement;
  const T *tmp;
  while (ptr->child) {
    tmp = ptr->child->compareElement;
    if (tmp != 0 && func(*tmp, *maySecond))
      maySecond = tmp;
    ptr = ptr->child;
  }
  for (int i = destructor.size() - 1; i >= 0; i--)
    delete [] destructor.at(i);
  return maySecond;
}

//最好不要比较double值,不精确,此处只是展示
bool compDouble(const double &a, const double &b)
{
  return a < b;
}
int main ( int argc, char *argv[] )
{

  int a[10] = {90, 234, 234, 11, 5435, 89, 2423, 122, 99, 99};

  const int *tmp = findSecond(a, 10, compInt);
  std::cout << *tmp << std::endl;

  double b[9] = {23.33, 2342.22, 12.33, 2134.222, 5555.33, 242.2, 888,
                 1.333, 2342.222};

//最好不要比较double值,不精确,此处只是展示
  const double *tmpDouble = findSecond(b, 9, compDouble);
  std::cout << *tmpDouble << std::endl;
  return 0;
}       /* ----------  end of function main  ---------- */

计数排序和基数排序的实现。。

本想模板编程,无奈基本没使用过,最后出来个四不像。。。。既不简单明了,又不高聚合低耦合的。。。

过几天再修改,将所有算法都尽量做成模板性质。。

#include <iostream>

int intFunc(int *number, void *)
{
  return *number;
}
// intbit 获取整数的第dbit位
int intbit(int *number, void *dbit);
/*
 * ===  FUNCTION  ======================================================================
 *         Name:  CountingSort
 *  Description:  计数排序计数提供了O(N)的排序算法。
 *  但受限于整数的Range,是一个用空间换取时间的算法。
 *  rangeArr的依次相加获取数组位置是为了稳定排序,适用于各种可由正整数排序的结构。
 *  限制:必须是0开始的有range的正整数(可以通过func转换为此,再进行排序)
 * =====================================================================================
 */
template <typename T>
struct PosWithPointer {
  int posValue;
  T *pointer;
};

template <typename T>
void CountingSort(T *array, int size, int range, int(*func)(T *element, void *), void *arg = 0)
{
     PosWithPointer<T> *rangeArr = new PosWithPointer<T>[range +1];
     for (int i = 0; i <= range; i++) {
          rangeArr[i].posValue = 0;
          rangeArr[i].pointer = 0;
     }
     for (int i = 0;  i < size; i++) {
          ++rangeArr[func(array + i, arg)].posValue;
          rangeArr[func(array +i, arg)].pointer = array + i;
     }

     for (int i = 1; i <= range; i++) {
          rangeArr[i].posValue += rangeArr[i - 1].posValue;
     }

     T *sortArray = new T[size];
     for (int i = size - 1; i >= 0; --i) {
          // 注意此处要 -1,因为最小的数据位置为1,而数组初始为0.
          sortArray[rangeArr[func(array + i, arg)].posValue - 1] = array[i];
          --rangeArr[func(array +i, arg)].posValue;
     }
     for (int i = 0; i < size; i++) {
          array[i] = sortArray[i];
     }
     delete [] rangeArr;
     delete [] sortArray;

}

int tenPow(int basePow)
{
  int result = 1;
  for (int i = 1; i <= basePow; i++)
    result *= 10;
  return result;
}

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  RadixSort
 *  Description:  借助于计数排序的RaDixSort;
 *  算法复杂度:线性 O(dbit(size+ 10)), 10为每一位可能的取值
 * =====================================================================================
 */
// Dgit为数字的最大位数
void RadixSort(int *array, int size, int dbit)
{
  for (int i = 1; i <= dbit; i++)
    CountingSort(array, size, tenPow(dbit), intbit, static_cast<void *>(&i));
}

int intbit(int *number, void *dbit)
{
  if (*number < 0)
    return 0;
 
  int *bit = static_cast<int *>(dbit);
  return *number / tenPow(*bit - 1) % 10;
}

int main(int argc, char **argv)
{
     int a[10] = {3, 5, 3, 2, 8, 984, 223, 82, 9234, 10};
     std::cout << "计数排序数组" << std::endl;
     CountingSort(a, 10, 9235, intFunc, 0);
     for (int i = 0; i < 10; i++) {
          std::cout << a[i] << "\t";
     }

     std::cout << "\n使用基数排序,底层用计数排序实现" << std::endl;
     int b[10] = {3, 5, 3, 2, 8, 984, 223, 82, 9234, 10};
     RadixSort(b, 10, 4);
     for (int i = 0; i < 10; i++) {
          std::cout << b[i] << "\t";
     }

     return 0;
}

 

继续阅读

算法导论中关于堆的习题解决。6.5-8 k路链表排序 6-3Young氏矩阵

最大/最小优先级的结构代码不再赘述,需要考虑C/C++编程中0为初始,从而在代码上修改即可。

如有需要,我会给出我的。。。

 

问题:6.5-8

给出一个时间为O(nlgk),用来将k个已排序链表合并为一个排序链表的算法。n为所有输入链表中元素的总数。(提示:用一个最小堆来做k路合并)

答案:

所有比较以多路链表首元素为基数,并以此来建立最小优先级队列。

总是弹出根节点链表的首元素。每次弹出后,如果根节点已经0元素,就extract-min(),否则minHeapify()下移根节点(有可能仍是最小元素,不必小移)。

 

问题: 6-5

Young氏矩阵:

答案:

(1)Extract-Min()

将第一个元素保存,最后返回。

Y[m,n](最大的)与第一个元素交换,并比较最大元素的行/列两个临近元素,取小的值与最大值交换。注意边界,递归。

(2)排序:

将每个元素放入y[m,n],然后运行Extract-Min

n^2个元素需要2n^3的运行时间。

(3)查找:

总是与最右上角比较,如果等于,则返回。

如果大于,去除这一行

如果小于,去除这一列。。

单链表,双向链表,栈ADT

/*
 * =====================================================================================
 *       Filename:  list.h
 *    Description:  链表ADT
 *
 *        Version:  1.0
 *        Created:  2011年03月19日 20时29分27秒
 *         Author:  hohosd44 (), sd44sd44@yeah.net
 *        Company:  
 * =====================================================================================
 */

typedef int elem_t;

#ifndef _LIST_H_
#define _LIST_H_
#include    <stdio.h>
#include    <stdlib.h>
#include    <stdbool.h>
 
typedef struct node {
    elem_t element;
    struct node *next;
} Node;
 
typedef Node *List;
typedef Node *Position;
 
List initialization(void);
bool isempty(List);
bool islast(Position, List);
Position find(elem_t, List);
Position findprev(elem_t, List);
void deletes(elem_t, List);
void insert(elem_t, List, Position);
void deletelist(List);
bool additem(elem_t, List);
 
#endif
 
List initialization(void)
{
    Position l;
    l = (List) malloc(sizeof(Node));
    if (l == NULL)
        fprintf(stderr, "%s\n", "Out of memory!");
    l->next = NULL;
    return l;
}
 
bool isempty(List l)
{
    return l->next == NULL;
}
 
bool islast(Position y, List l)
{
    return y->next == NULL;
}
 
Position find(elem_t x, List l)
{
    Position tmp;
    tmp = l->next;
    while (tmp != NULL && tmp->element != x)
        tmp = tmp->next;
 
    return tmp;
}
 
Position findprev(elem_t x, List l)
{
    Position tmp;
    tmp = l;
    while (tmp->next != NULL && tmp->next->element != x)
        tmp = tmp->next;
 
    return tmp;
}
 
void deletes(elem_t x, List l)
{
    Position prevpos, tmp;
    prevpos = findprev(x, l);
 
    if (!islast(prevpos, l)) {
        tmp = prevpos->next;
        prevpos->next = tmp->next;
        free(tmp);
    }
}
 
void insert(elem_t x, List l, Position y)
{
    Position tmppos;
    tmppos = (Position) malloc(sizeof(Node));
    if (tmppos == NULL)
        fprintf(stderr, "%s\n", "out of space!!!");
    tmppos->element = x;
    tmppos->next = y->next;
    y->next = tmppos;
}
 
void deletelist(List l)
{
    Position tmppos, tmp2pos;
 
    tmppos = l->next;
    while (tmppos != NULL) {
        tmp2pos = tmppos->next;
        free(tmppos);
        tmppos = tmp2pos;
    }
    free(l);
}
 
bool additem(elem_t x, List l)
{
    Position tmppos = l->next;
    Position newpos;
 
    newpos = (Position) malloc(sizeof(Node));
    if (newpos == NULL) {
        fprintf(stderr, "%s\n", "Out of space!!!");
        return false;
    }
 
    newpos->element = x;
    newpos->next = NULL;
 
    if (tmppos == NULL)
        l->next = newpos;
    else {
        while (tmppos->next != NULL) {
            tmppos = tmppos->next;
        }
        tmppos->next = newpos;
    }
    return true;
 
}

// 双链表ADT
typedef int elem_t;
#ifndef _LIST_H_
#define _LIST_H_
 
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
    elem_t element;
    struct node *prev;
    struct node *next;
} Node;
 
typedef Node *List;
typedef Node *Position;
 
List initialization(void);
bool isempty(List);
bool islast(Position, List);
Position find(int , List);
Position findprev(int, List);
void deletes(elem_t, List);
void insert(elem_t, List, Position);
void deletelist(List);
bool additem(elem_t, List);
 
#endif
 
List initialization(void)
{
    Position l;
    l = (List) malloc(sizeof(Node));
    if (l == NULL)
        fprintf(stderr, "%s\n", "Out of memory!");
    l->prev = NULL;
    l->next = NULL;
    return l;
}
 
bool isempty(List l)
{
    return l->next == NULL;
}
 
bool islast(Position y, List l)
{
    return y->next == NULL;
}
 
Position find(elem_t x, List l)
{
    Position tmp;
    tmp = l->next;
    while (tmp != NULL && tmp->element != x)
        tmp = tmp->next;
 
    return tmp;
}
 
Position findprev(elem_t x, List l)
{
    Position tmp;
    tmp = l;
    while (tmp->next != NULL && tmp->next->element != x)
        tmp = tmp->next;
 
    return tmp;
}
 
void deletes(elem_t x, List l)
{
    Position prevpos, tmp;
    prevpos = findprev(x, l);
 
    if (!islast(prevpos, l)) {
        tmp = prevpos->next;
        prevpos->next = tmp->next;
        tmp->next->prev = prevpos;
        free(tmp);
    }
}
 
void insert(elem_t x, List l, Position y)
{
    Position tmppos;
    tmppos = (Position) malloc(sizeof(Node));
    if (tmppos == NULL)
        fprintf(stderr, "%s\n", "out of space!!!");
    tmppos->element = x;
    tmppos->prev = y;
    tmppos->next = y->next;
    y->next->prev = tmppos;
    y->next = tmppos;
}
 
void deletelist(List l)
{
    Position tmppos, tmp2pos;
 
    tmppos = l->next;
    while (tmppos != NULL) {
        tmp2pos = tmppos->next;
        free(tmppos);
        tmppos = tmp2pos;
    }
    free(l);
}
 
bool additem(elem_t x, List l)
{
    Position tmppos = l->next;
    Position newpos;
 
    newpos = (Position) malloc(sizeof(Node));
    if (newpos == NULL) {
        fprintf(stderr, "%s\n", "Out of space!!!");
        return false;
    }
 
    newpos->element = x;
    newpos->next = NULL;
 
    if (tmppos == NULL) {
        l->next = newpos;
        newpos->prev = l;
    } else {
        while (tmppos->next != NULL) {
            tmppos = tmppos->next;
        }
        tmppos->next = newpos;
        newpos->prev = tmppos;
    }
    return true;
}

/*
 * =====================================================================================
 *       Filename:  stack.c
 *    Description:  栈链表ADT
 *
 *        Version:  1.0
 *        Created:  2011年03月20日 14时17分49秒
 *         Author:  hohosd44 (), sd44sd44@yeah.net
 *        Company:  
 * =====================================================================================
 */

#include	<stdbool.h>
#include	<stdlib.h>
#include	<stdio.h>

#ifndef  _stack_h__INC
#define  _stack_h__INC

typedef int elementtype;

struct node;
typedef struct node Node;
typedef Node *Stack;
typedef Node *Position;

bool isempty(Stack s);
Stack creatstack(void);
void freestack(Stack s);
void makeempty(Stack s);
void push(elementtype x, Stack s);
elementtype pop(Stack s);

#endif /* ----- #ifndef _stack_h__INC  ----- */

struct node {
	elementtype x;
	Position next;
};

bool isempty(Stack s)
{
	return s->next == NULL;
}

Stack creatstack(void)
{
	Stack s;
	s = (Position) malloc(sizeof(Node));

	if (s == NULL) {
		fprintf(stderr, "Out of space!!!");
		exit(1);
	}

	s->next = NULL;
	makeempty(s);
	return s;
}

void freestack(Stack s)
{
	makeempty(s);
	free(s);
}

void makeempty(Stack s)
{
	if (s == NULL) {
		fprintf(stderr, "Out of space!!!");
		exit(1);
	}
	while (!isempty(s))
		pop(s);
}

void push(elementtype x, Stack s)
{
	Position tmp;
	tmp = (Position) malloc(sizeof(Node));
	tmp->x = x;
	tmp->next = s->next;
	s->next = tmp;
}

elementtype pop(Stack s)
{
	Position tmp1;
	elementtype tmpdata;

	if (!isempty(s)) {
		tmpdata = s->next->x;
		tmp1 = s->next;
		s->next = s->next->next;
		free(tmp1);
		return tmpdata;
	} else {
		fprintf(stderr, "Empty Stack!!");
		exit(1);
	}
}

 

一些小题

#include <stdio.h>

int majority(int [], int, int);                 /* 确认候选值是不是主要元素 */
int primarykey(int arr[], int n)                /* 找出候选值 */
{
    int gal = 1;
    int key = arr[0];
    int i;
    for (i = 1; i < n; i++) {
        if (key == arr[i]) {
            gal++;
        }
        else
            gal--;
        if (gal == 0) {
            gal = 1;
            key = arr[i];
        }
    }
    return majority(arr, n, key);
}

int majority(int a[], int n, int key)
{
    int i;
    int sumkey = 0;
    for (i = 0; i < n; i++)
        if (a[i] == key)
            sumkey++;
    if (sumkey > n / 2)
        return key;
    else
        return 0;
}
int main(void)
{
    int a[] = {3, 3, 4, 3, 3, 4, 2, 4, 3};
    printf("%d\n", primarykey(a, 8));
    printf("%d\n", primarykey(a, 9));
    return 0;
}

 

啊啊