现在的位置: 首页 > 综合 > 正文

第十七篇–算法导论第十章习题选解

2013年01月09日 ⁄ 综合 ⁄ 共 5453字 ⁄ 字号 评论关闭

10-1-2:

两个栈分别从数组的两端开始,向中间扩展;

10-1-5:

这个deque的代码以前的实现过(c++ STL),这里就不写了。这里的head和tail一开始都指向数组的中间位置即可;

10-1-6:

栈是先进后出,队列是先进先出,

对于由两个栈实现一个队列,根据负负得正的原则,一开始先将元素加入栈1,等到删除元素时,先将元素删除到栈2,然后通过栈2出栈,然后继续,等到栈2中的元素都删除完了,再进行栈1元素全部清空到栈2。

这里使用stack类构造queue类,参见栈和队列代码,

其中对于stack代码的改动是添加friend声明;

template<typename T,typename Alloc=alloc>
class queue
{
private:
	stack<T,Alloc> _stack1;
	stack<T,Alloc> _stack2;
	int capacity;

public:
	queue(int queueCapacity=10);//构造队列,默认容量为10;  
	bool Empty() const{return _stack1.Empty() && _stack2.Empty();}  
    T& Front() ;//返回队列头部元素  
    T& Rear() ;//返回队列尾部元素  
    void Push(const T& x);//插入元素,只能在队列尾部插入  
    void Pop();//删除元素,只能在队列头部删除 
};
//----------------------------------------------------------------------------------------
template<typename T,typename Alloc>  
queue<T,Alloc>::queue(int queueCapacity)  
    :capacity(queueCapacity)  
{  
    if(capacity<1) throw"queue capacity must >0";  
	_stack1.capacity=queueCapacity;
	_stack1.allocate_and_fill(10,T());
}  
//-------------------------------------------------------------------------------------------  
template<typename T,typename Alloc>  
 T&  queue<T,Alloc>::Front() 
{  
    if(Empty()) throw"queue is empty";
	if(_stack2.Empty()){//此时栈2为空,我们需要获取的元素必然是栈2的栈顶元素,所以需要先把
		//栈1中的元素全部清空到栈2,
		T tmp;
		while(!_stack1.Empty()){
			tmp=_stack1.Top();
			_stack2.Push(tmp);
			_stack1.Pop();
		}
	}
	return _stack2.Top();
}
 //---------------------------------------------------------------------------------------------
template<typename T,typename Alloc>  
 T& queue<T,Alloc>::Rear() 
{  
    if(Empty()) throw"queue is empty";  
	if(_stack1.Empty()){
		return _stack2._stack[0];
	}else{
		return _stack1.Top();
	}
}  
//-------------------------------------------------------------------------------------------  
template<typename T,typename Alloc>  
inline void queue<T,Alloc>::Push(const T& x)  
{  
	_stack1.Push(x);
}  
//------------------------------------------------------------------------------------------ ----   
template<typename T,typename Alloc>  
void queue<T,Alloc>::Pop()  
{  
    if(Empty()) throw" queue is empty";  
	if(_stack2.Empty()){//此时栈2为空,我们需要获取的元素必然是栈2的栈顶元素,所以需要先把
		//栈1中的元素全部清空到栈2,
			while(!_stack1.Empty()){
			_stack2.Push(_stack1.Top());
			_stack1.Pop();
		}
	}
	_stack2.Pop();
}  

10-1-7:

这里正正是不能得负的。

这里的实现很没有技巧性,看过别人的解题方法,都是一个思路,当要出栈的时候,就把一个队列中的前n-1个元素全部倾倒到另一个队列中,然后队列剩下的最后一个元素出栈;

或者从开始入栈的时候,两个队列中,其中一个是空队列,将值入这个空队列,然后将另一个非空队列的值依次取出并加入这个队列中;


10-2-8:

此处http://blog.csdn.net/mishifangxiangdefeng/article/details/7706631非常详细,主要是怎么由np获得prev和next

10-4-x:

//---------------------------------------------------------------------------------------
template<typename T>
struct _tree_node
{
	T data;
	_tree_node<T>*  left_child;
	_tree_node<T>* right_child;
	_tree_node(T a=T(),_tree_node<T>* b=NULL,_tree_node<T>* c=NULL)
		:data(a),left_child(b),right_child(c){ }

};

template<typename T,typename Alloc=alloc>
class tree
{
private:
typedef _tree_node<T>  tree_node;
typedef simple_alloc<tree_node,Alloc> node_allocator;
//这里主要考虑的是树的遍历问题
public:
	void Inorder(tree_node* current_node);//中序遍历
	void Iterative_Inorder(tree_node* current_node);//迭代中序遍历
	void Preorder(tree_node* current_node);//先序遍历
	void Postorder(tree_node* current_node);//后序遍历
	void level_order(tree_node* current_node);//层次遍历
private:
	tree_node* root;
private:
	void Visit(tree_node* current_node);//表示访问某一节点
};
//-----------------------------------------------------------------------------------
template<typename T,typename Alloc>
void tree<T,Alloc>::Inorder(tree_node* current_node)
{
	if(current_node){
		Inorder(current_node->left_child);
		Visit(current_node);
		Inorder(current_node->right_child);
	}
}
//-----------------------------------------------------------------------------------
template<typename T,typename Alloc>
void tree<T,Alloc>::Preorder(tree_node* current_node)
{
	if(current_node){
		Visit(current_node);
		Preorder(current_node->left_child);
		Preorder(current_node->right_child);
	}
}
//--------------------------------------------------------------------------------
template<typename T,typename Alloc>
void tree<T,Alloc>::Postorder(tree_node* current_node)
{
	if(current_node){
		Postorder(current_node->left_child);
		Postorder(current_node->right_child);
		Visit(current_node);
	}
}
//---------------------------------------------------------------------------------
//完全模拟的是递归算法的执行过程,由显式的程序调用栈转化为我们自己的栈
template<typename T,typename Alloc>
void tree<T,Alloc>::Iterative_Inorder(tree_node* current_node)
{
	stack<tree_node*> s;
	tree_node* _current_node=current_node;
	while(1){
		while(_current_node){
			s.Push(_current_node);
			_current_node=_current_node->left_child;
		}
		if(s.Empty()) return;
		_current_node=s.Top();
		s.Pop();
		Visit(_current_node);
		_current_node=_current_node->right_child;
	}
}
//-------------------------------------------------------------------
//访问节点,此处我们是打印节点的值到cout
template<typename T,typename Alloc>
void tree<T,Alloc>::Visit(tree_node* current_node)
{
	std::cout<<current_node->data<<' ';
}
//-----------------------------------------------------------------------------------------
//使用队列的思想
template<typename T,typename Alloc>
void tree<T,Alloc>::level_order(tree_node* current_node)
{
	queue<tree_node*> q;
	tree_node* _current_node=current_node;
	while(_current_node){
		Visit(_current_node);
		if(_current_node->left_child) q.Push(_current_node->left_child);
		if(_current_node->right_child) q.Push(_current_node->right_child);
		if(q.Empty()) return;
		_current_node=q.Front();
		q.Pop();
	}
}
//-------------------------------------------------------------------------------------

10-4-5:

这里要求的是使用固定量的额外空间,一种方法是增加parent域,但是这种方法会造成巨大的空间代价,远不如使用栈来的划算;

使用这种方法,仍然模拟的是中序遍历的执行过程,只是这里并不是使用栈,而是采用parent索引;

第二种方法是使用线索树:由于叶结点的left_child和right_child域都是没使用的,我们可以充分利用这些空间:

如果节点p的right_child为空,那么设置right_child指向p在中序遍历时的后继节点;

如果节点p的left_child为空,那么设置left_child指向p在中序遍历时的前驱节点;

同时节点增加两个域,bool型的:left_thread和right_thread,当值为true时,对应的孩子节点是线索;

10-4-6:

线索树




抱歉!评论已关闭.