《数据结构与算法描述:c++实现》第3版第三章课后练习答案

《数据结构与算法描述:c++实现》第3版第三章课后练习答案


3.1 给定一个链表L和另一个链表P,包含以升序排列的整数。操作printLots(L,P)将打印L中那些由P指定的位置上的元素,例如,P = 1,3,4,6,那么L中的第1,3,4,6的元素被打印出来。使用公有的STL容器操作,运行时间为多少。

#include 
#include 
#include 
#include 
#include 
#include
using namespace std;
//3.1 
template <typename Object>
void printLots(list<Object> L, list<int> P)
{
	typename list<int>::const_iterator pIt;
	typename list<Object>::const_iterator lIt;
	for (pIt = P.begin(); pIt != P.end(); pIt++)
	{
		int num = *pIt;
		int printNum = 0;
		for (lIt = L.begin(); lIt != L.end(); lIt++)
		{
			printNum++;
			if (printNum == num)
				break;
		}
		cout << *lIt << "  ";

	}
	cout << endl;
}
int main()
{
	list<int> lst1;
	list<int> lst2;
	lst1.push_front(1);	lst1.push_front(3);	lst1.push_front(5);	lst1.push_front(2);
	lst1.push_front(7);	lst1.push_front(9);	lst1.push_front(25);lst1.push_front(11);
	lst2.push_front(4);	lst2.push_front(1);	lst2.push_front(3);	lst2.push_front(6);
	lst1.sort();
	lst2.sort();
	cout << "List L:";
	for (list<int>::iterator i = lst1.begin(); i != lst1.end(); i++)
		cout << *i << "  " ;
	cout << endl;
	cout << "List P:";
	for (list<int>::iterator i = lst2.begin(); i != lst2.end(); i++)
		cout << *i << "  ";
	cout << endl;
	clock_t startTime, endTime;
	startTime = clock();//计时开始
	printLots(lst1, lst2);
	endTime = clock();//计时结束
	cout << "The run time is: " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
	system("pause");
	return 0;
}


执行结果如下:
在这里插入图片描述
3.2 通过只调整链(而不是数据)来交换相邻的元素,使用a.单向链表,b.双向链表

void swapWithSingleNext(Node * beforep)
{
  Node *p , *afterp;
  p = before->next;
  afterp = p->next; // both p and afterp assumed not NULL
  p->next = afterp-> next;
  beforep ->next = afterp;
  afterp->next = p;
}

void swapWithDoubleNext(Node *p)
{
  Node *beforep, *afterp;
  beforep = p->prev;
  afterp = p->next;
  p->next = afterp->next;
  beforep->next = afterp;
  afterp->next = p;
  p->next->prev = p;
  p->prev = afterp;
  afterp->prev = beforep;
  }

3.3 实现STL的find例程,该例程返回的iterator包含从start开始一直到end(不包含end)的范围内第一个出现的x。如果x没有找到,就返回end。该非类全局函数的签名如下:
template
iterator find(Iterator start, Iterator end, const Object & x)

template<typename Iterator, typename Object>
iterator find(Iterator start, Iterator end, const Object & x)
{
	Iterator iter;
	for (iter = start; iter!= end; iter++)
	{
		if (*iter == x || iter == end)
			break;
	}
	return iter;
}

3.4 给定两个排序后的表L1和L2,写出一个程序仅使用基本的表操作来计算L1∩L2

template <typename Object>
list<Object> intersection(const list<Object> & L1,const list<Object> & L2)
{
	list<Object> intersect;
	typename list<Object>::const_iterator iterL1 = L1.begin();
	typename list<Object>::const_iterator iterL2 = L2.begin();
	while (iterL1 != L1.end() && iterL2 != L2.end())
	{
		if (*iterL1 == *iterL2)
		{
			//有相同的元素
			intersect.push_back(*iterL1);
			iterL1++;
			iterL2++;
		}
		//L1的元素小,所以需要1的指针往后找
		else if (*iterL1 < *iterL2)
			iterL1++;
		else
			iterL2++;
	}
	return intersect;
}

3.5 给定两个排序后的表L1和L2,写出一个程序仅使用基本的表操作来计算L1∪L2

template <typename Object>
list<Object> intersection(const list<Object> & L1, const list<Object> & L2)
{
	list<Object> intersect;
	typename list<Object>::const_iterator iterL1 = L1.begin();
	typename list<Object>::const_iterator iterL2 = L2.begin();
	while (iterL1 != L1.end() && iterL2 != L2.end())
	{
		if (*iterL1 == *iterL2)
		{
			//有相同的元素
			intersect.push_back(*iterL1);
			iterL1++;
			iterL2++;
		}
		//L1的元素小,所以需要1的指针往后找
		else if (*iterL1 < *iterL2)
		{
			intersect.push_back(*iterL1);
			iterL1++;
		}
		else
		{
			intersect.push_back(*iterL2);
			iterL2++;
		}
			
	}
	return intersect;
}

3.6 Josephus问题是下面这个游戏,有N个人坐成一圈,编号1到N,从编号为1的人开始传递热马铃薯。M次传递之后,持有热马铃薯的人退出游戏,圈缩小,然后游戏从退出人下面的人开始,继续进行,最终留下来的人获胜,这样,如果M=0并且N=5,那么参加游戏的人依次退出,5号获胜。如果M=1并且N=5,那么退出的顺序就行2,4,1,5
a.写一个程序解决Josephus问题,此时M和N为任意值,尽可能使程序高效,同时确保存储单元被正确处理。
b.程序运行的时间
c.M=1时,运行时间为多少?对于N的较大值,delete例程对程序运行速度的影响有多大

int main()
{
	int m, n, numLeft, mPrime;
	list<int> L;
	list<int>::iterator iter;
	cout << "Please enter the total num N and pass times M:" << endl;
	cin >> n >> m;
	numLeft = n;
	mPrime = m % n;
	for (int i = 1; i <= n; i++)
	{
		mPrime = mPrime % numLeft;
		if (mPrime <= numLeft / 2)//out
		{
			for (int j = 0; j < mPrime; j++)
			{
				iter++;
				if (iter == L.end())
					iter = L.begin();
			}
		}
			
		else // pass backward
		{
			for (int j = 0; j < mPrime; j++)
			{
				if (iter == L.begin())
					iter = --L.end();
				else
					iter--;
			}
		}
		cout << *iter << " ";
		iter = L.erase(iter);
		if (iter == L.end())
			iter = L.begin();
	}
	cout << endl;
	system("pause");
	return 0;
}

3.7 修改Vector类,添加索引时的边界检测功能

Object & operator[](int index)
{
	if (index >= 0 && index <size())
		return objects[index];
	else
		cout << "index out of bounds\n";
	return objects[0];
}
const Object & operator[](int index) const
{
	if (index >= 0 && index <size())
		return objects[index];
	else
		cout << "index out of bounds\n";
	return objects[0];
}

3.8 给Vector类添加insert和erase

iterator insert(iterator pos, const Object& x)
{
  Object * iter = &objects[0];
  Object *oldArray = objects;
  theSize++;
  int i;
  if (theCapacity < theSize)
    theCapactiy = theSize;
  objects = new Object[ theCapacity ];
  while(iter != pos)
  {
   objects[i]= oldArray[i];
   iter += sizeOf(Object);
   pos += sizeOf(Object);
   i++;
  }
  objects[pos] = x;
  for (int k = pos+1; k < theSize; k++)
    objects[k] = oldArray[ k ];
  delete [ ] oldArray;
  return & objects[pos];
} 

3.9 对于vector,按照c++标准,对push_back, pop_back, inset, erase的调用将使所有指向vector的迭代器失效,为什么?
所有上述功能可能需要创建一个新的数组来保存数据。 当发生这种情况的时候,所有旧的指针(迭代器)均无效。
3.10 修改vector类,通过赋予迭代器类型而不是指针变量,来提供严格的迭代器检验,正如3.9所说的那样,最困难的部分是处理失效的迭代器。
更改为const_iterator类,迭代器类以及对使用或返回迭代器的所有Vector函数的更改。 这些类和函数显示在以下三个中

class const_iterator
{
  public:
//const_iterator( ) : current( NULL )
// { } Force use of the safe constructor
  const Object & operator* ( ) const
    { return retrieve( ); }
  const_iterator & operator++ ( )
    {
     current++;
     return *this;
     }
  const_iterator operator++ ( int )
   {
    const_iterator old = *this;
    ++( *this );
   return old;
}
bool operator== ( const const_iterator & rhs ) const
  { return current == rhs.current; }
bool operator!= ( const const_iterator & rhs ) const
  { return !( *this == rhs ); }
protected:
  Object *current;
  const Vector<Object> *theVect;
  Object & retrieve( ) const
   {
    assertIsValid();
    return *current;
   }
  const_iterator( const Vector<Object> & vect, Object *p ) :theVect (& vect), current( p )  { }
  void assertIsValid() const
  {
   if (theVect == NULL || current == NULL )
      throw IteratorOutOfBoundsException();
   }
   friend class Vector<Object>;
};
(b) 
class iterator : public const_iterator
{
 public:
  //iterator( )
  // { } Force use of the safe constructor
  Object & operator* ( )  { return retrieve( ); }
const Object & operator* ( ) const  { return const_iterator::operator*( ); }
iterator & operator++ ( )
{
  cout<<"old "<<*current<<" ";
  current++;
  cout<<" new "<<*current<<" ";
  return *this;
}
iterator operator++ ( int )
 {
  iterator old = *this;
  ++( *this );
  return old;
  }
protected:
  iterator(const Vector<Object> & vect, Object *p ) : const_iterator(vect, p ) { }
  friend class Vector<Object>;
};
(c) 
iterator begin( )
    { return iterator(*this ,&objects[ 0 ]); }
const_iterator begin( ) const
    { return const_iterator(*this,&objects[ 0 ]); }
iterator end( )
    { return iterator(*this, &objects[ size( ) ]); }
const_iterator end( ) const
    { return const_iterator(*this, &objects[ size( ) ]); }

3.11 假设一个单向链表的实现有一个表头结点,但是没有尾结点,并且只有一个指向表头结点的指针。写一个类,使之包括的方法可以
a 返回链表的大小
b 打印链表
c 检测值x是否在链表中
d 如果值x没在链表中,加入链表
e 如果值x包含在链表中,删除这个值

template <typename Object>
struct Node
{
	Object data;
	Node *next;
	Node(const Object & d = Object(), Node *n = NULL) : data(d), next(n) {}
};
template<typename Object>
class SingleList
{
public:
	SingleList(){ init(); }
	~SingleList(){ eraseList(head); }

	SingleList(const SingleList & rhs)
	{
		eraseList(head);
		init();
		*this = rhs;
	}

	bool add(Object x)
	{
		if (contains(x))
			return false;
		else
		{
			Node<Object> *ptr = new Node<Object>(x);
			ptr->next = head->next;
			head->next = ptr;
			theSize++;
		}
		return true;
	}

	bool remove(Object x)
	{
		if (!contains(x))
			return false;
		else
		{
			Node<Object>*ptr = head->next;
			Node<Object>*trailer;
			while (ptr->data != x)
			{
				trailer = ptr;
				ptr = ptr->next;
			}
			trailer->next = ptr->next;
			delete ptr;
			theSize--;
		}
		return true;
	}

	int size() { return theSize; }

	void print()
	{
		Node<Object> *ptr = head->next;
		while (ptr != NULL)
		{
			cout << ptr->data << " ";
			ptr = ptr->next;
		}
		cout << endl;
	}

	bool contains(const Object & x)
	{
		Node<Object> * ptr = head->next;
		while (ptr != NULL)
		{
			if (x == ptr->data)
				return true;
			else
				ptr = ptr->next;
		}
		return false;
	}

	void init()
	{
		theSize = 0;
		head = new Node<Object>;
		head->next = NULL;
	}

	void eraseList(Node<Object> * h)
	{
		Node<Object> *ptr = h;
		Node<Object> *nextPtr;
		while (ptr != NULL)
		{
			nextPtr = ptr->next;
			delete ptr;
			ptr = nextPtr;
		}
	};

private:
	Node<Object> *head;
	int theSize;

};

3.13 给List迭代器添加对operator–的支持

const_iterator & operator-- ( )
 {
  current = current->prev;
  return *this;
 }
const_iterator operator-- ( int )
 {
  const_iterator old = *this;
  --( *this );
  return old;
 }

3.14 读STL迭代器的值需要使用operator++操作,该操作依次推进迭代器。在某些情况下,读表中下一项的值而不推进迭代器也许更好。写出如下声明的成员函数来实现一般情况下的这个功能

 const_iterator & operator+ ( int k )
{
  const_iterator advanced = *this;
  for (int i = 0; i < k ; i++)
    advanced.current = advanced.current->next;
   return advanced;
} 

3.15 给List类添加splice操作,声明如下:
void splice(iterator position,List & lst)
删除lst中所有项,并将这些项放在List * this中的位置position前。lst和*this必须是不同的表。

void splice (iterator itr, List<Object> & lst)
  {
  itr.assertIsValid();
  if (itr.theList != this)
     throw IteratorMismatchException ();
  Node *p = iter.current;
  theSize += lst.size();
  p->prev->next = lst.head->next;
  lst.head->next->prev = p->prev;
  lst.tail->prev->next = p;
   p->prev = lst->tail->prev;
  lst.init();
  }

3.16

const_reverse_iterator rbegin() const
{
  return const_reverse_iterator itr( tail);
}

const_reverse_iterator rend() const
 {
  const_reverse_iterator itr(head);
  }

 reverse_iterator rbegin()
 {
   return reverse_iterator itr( tail);
  }

reverse_iterator rend()
 {
   reverse_iterator itr(head);
  }

3.17

For the  class const_iterator

 const_iterator( ) : current( nullptr )
 { }
 
 const Object & operator* ( ) const
 {
	 assertIsValid();
	 return retrieve( ); 
 }

 const_iterator & operator++ ( )
 {
  assertIsValid();
 current = current->next;
 return *this;
 }

 const_iterator operator++ ( int )
 {
 assertIsValid();
 const_iterator old = *this;
 ++( *this );
 return old;
 }

 protected:
 Node *current;
 const List<Object> *theList;
 const_iterator(const List<Object> &lst, Node *p) : theList(&lst),current(p) 
 {}

 void assertIsValid() const
 {
   if (theList == nullptr || current == nullptr || current == theList->head)
	   throw IteratorOutOfBoundsException();
 }

For the class class iterator : public const_iterator

 Object & operator* ( )
 {
	 assertIsValid();

	 return const_iterator::retrieve( ); 
 }
 const Object & operator* ( ) const
 { 
	 assertIsValid();
	 return const_iterator::operator*( ); 
 }

 iterator & operator++ ( )
 {
  assertIsValid();
 this->current = this->current->next;
 return *this;
 }

 iterator operator++ ( int )
 {
  assertIsValid();
 iterator old = *this;
 ++( *this );
 return old;
 }

 protected:
 iterator(const List<Object> & lst, Node *p ): const_iterator(lst,p)
 { }

For the List class 
iterator begin( )
 { iterator itr(*this, head);
	 return (++itr );
 }
 const_iterator begin( ) const
 { const_iterator itr(*this, head);
	 return ( ++itr ); 
 }
 iterator end( )
 { iterator itr(*this, tail);
	 return ( itr ); 
 }
 const_iterator end( ) const
 {
   iterator itr(*this, tail);
	 return ( itr ); 
 }


 iterator insert( iterator itr, const Object & x )
 { 
  itr.assertIsValid();
  if (itr.theList != this)
	  throw IteratorMismatchException();

   Node *p = itr.current;
   theSize++;
   return (*this, p->prev = p->prev->next = new Node( x, p->prev, p ) );
 }

 iterator insert( iterator itr, Object && x )
 {
  itr.assertIsValid();
  if (iter.theList != this)
	  throw IteratorMismatchException();

  Node *p = itr.current;
  theSize++;
  return { p->prev = p->prev->next
               = new Node{ std::move( x ), p->prev, p } };
 }

 iterator erase( iterator itr )
 { 
  Node *p = itr.current;

  itr.assertIsValid();
  if (itr.theList != this)
	  throw IteratorMismatchException();
  iterator retVal(*this, p->next );
  p->prev->next = p->next;
  p->next->prev = p->prev;
  delete p;
  theSize--;

 return retVal;
 }

 iterator erase( iterator from, iterator to )
 { 

 for( iterator itr = from; itr != to; )
{
    itr.assertIsValid();
  if (iter.theList != this)
	  throw IteratorMismatchException();

    itr = erase( itr );
	 }
  return to;
 }

3.18 如果节点处于活动状态,则将一个布尔数据成员添加到节点类;如果为true,则为true。 如果为“陈旧”,则为false。擦除方法将此数据成员更改为false;否则,方法为false。 迭代器方法验证该节点不是陈旧的。
3.19 没有头节点或尾节点,从末尾插入和删除的操作将变为O(N)操作,其中N是列表中元素的数量。 该算法必须先遍历列表,然后再插入末尾。 对于头节点,插入需要特殊情况来说明何时在第一个节点之前插入了某些内容。
3.20 优点在于,它更易于编码,并且如果随后重新插入已删除的密钥(在同一位置),则可能会节省成本。 缺点是它使用更多的空间,因为每个单元格需要一个额外的位(通常是一个字节),并且未使用的单元格不会被释放

void garbageCollection()
{
  Node *p = head->next;
  Node *q ;
  while (p!= tail)
  {
   if (p->deleted == true)
   {
	 q = p->prev;
	 p->prev->next = p->next;
     p->next->prev = p->prev;
     delete p;
	 p = q;
   }
   p = p->next;
  }
  numDeleted = 0;
}

 iterator erase( iterator itr )
 { 
  Node *p = itr.current;
  Node *q;  p->deleted = true;
  numDeleted ++;
  theSize--;
  if (numDeleted >= theSize)
    garbageCollection();
 iterator retVal(*this, p->next );
 return retVal;
 }

3.21

#include 
#include 
#include 
#include 
using namespace std;

int main()
{
  string fileName;
  stack<char> match;
  bool balanced = true;
  string line;
  ifstream in;
  int i;
  int lineNumber = 0;
  char x;

  cout<<"what is the name of the file: ";
  cin>>fileName;
  in.open(fileName.c_str());

  getline(in, line);
  while (in && balanced)
  {
    lineNumber++;
    for ( i= 0; i< line.size(); i++)
	{
	  x = line[i];
	  if (x == '\"') // skip chars in double quotes
	  {
	    i++;
		while (x != '\"')
			x++;
	  }
	   else if (x == '\'') // skip chars in single quotes
	  {
	    i++;
		while (x != '\'')
			x++;
	  }
      else if (x == '\\' && i < line.size()-1 && line[i+1] == '\\')
		  getline(in, line);
	  else if (x == '(' || x == '['|| x == '{')
		  match.push(x);
	  else if (x == ')')
	  {
	    if (match.top()!='(') balanced = false;
		match.pop();
	  }
	  else if (x == ']')
	  {
	     if (match.top()!='[') balanced = false;
		 match.pop();
	  }
	  else if (x == '}')
	  {
		if (match.top()!='{') balanced = false;
		match.pop();
	  }
	  else if (x == '/' && i < line.size() -1 && line[++i] == '*')
		 match.push('/');
	  else if (x== '*' && i < line.size() -1 && line[++i] == '/')
	  {
	    if (match.top()!='/') balanced = false;
	   match.pop();
	  }
	}
	getline(in, line);
  }
  if (balanced)
	  cout<<"the symbols balanced \n";
  else
	  cout<<"mismatched symbol on line "<<lineNumber<<endl;
}

3.22

double evalPostFix( )
{
  stack<double> s;
  string token;
  double a, b, result;
  cin>> token;
  while (token[0] !==)
  {
  result = atof (token.c_str());
  if (result != 0.0 )
     s.push(result); 
   else if (token == "0.0")
     s.push(result);
   else
  switch (token[0])
   {
     case+: a = s.top(); s.pop(); b = s.top();
                s.pop(); s.push(a+b); break;
     case-: a = s.top(); s.pop(); b = s.top();
                s.pop(); s.push(a-b); break;
     case*: a = s.top(); s.pop(); b = s.top();
                s.pop(); s.push(a*b); break;
     case/: a = s.top(); s.pop(); b = s.top();
                s.pop(); s.push(a/b); break;
     case^: a = s.top(); s.pop(); b = s.top();
                s.pop(); s.push(exp(a*log(b))); break;
    }
     cin>> token; 
   }
   return s.top();
}

3.23 a和b

void inToPostfix()
 {
   stack<char> s;
   char token;
   cin>> token;
   while (token !==)
   {
    if (token >= ’a’ && token <= ’z’)
      cout<<token<<" ";
    else
      switch (token)
      {
       case): while(!s.empty() && s.top() !=()
                  { cout<<s.top()<<" "; s.pop();}
                  s.pop(); break;
       case(: s.push(token); break;
        case^: while(!s.empty() && !(s.top()==^|| s.top() ==())
                   {cout<<s.top(); s.pop();}
                   s.push(token); break;
        case*:
        case/: while(!s.empty() && s.top() !=+&& s.top() !=-&& s.top() !=()
                   {cout<<s.top(); s.pop();}
                   s.push(token); break;
        case+:
        case-: while(!s.empty() && s.top() !=()
                   {cout<<s.top()<<’’ ‘‘; s.pop();}
                    s.push(token); break;
      }
      cin>> token;
   }
   while (!s.empty())
      {cout<<s.top()<<’’ ‘‘; s.pop();}
   cout<<ˇ = \nˇ;
  }

c

string postToInfix()
{
 stack<string> s;
 string token;
 string a, b;
 cin>>token;
 while (token[0] !==)
  {
   if (token[0] >= ’a’ && token[0] <= ’z’)
     s.push(token);
   else
    switch (token[0])
    {
     case+: a = s.top(); s.pop(); b = s.top(); s.pop();
                s.push("("+ a+" + " + b+")"); break;
     case-: a = s.top(); s.pop(); b = s.top(); s.pop();
                s.push("("+a+" - "+ b+")"); break;
     case*: a = s.top(); s.pop(); b = s.top(); s.pop();
                s.push("("+a+" * "+ b+")"); break;
     case/: a = s.top(); s.pop(); b = s.top(); s.pop();
                s.push("("+a+" / " + b+")"); break;
      case^: a = s.top(); s.pop(); b = s.top(); s.pop();
                s.push("("+a+" ^ " + b+")"); break;
    }
  cin>> token;
 }
return s.top();
} //Converts postfix to infix


3.24 在数组中可以实现两个堆栈,方法是使一个堆栈从数组的低端向上生长,而另一个从高端向下生长。

3.25(a)令E为我们的扩展堆栈。我们将使用两个堆栈来实现E。我们称其为S的一个堆栈用于跟踪推入和弹出操作,而另一个M则用于跟踪最小值。为了实现E.push(x),我们执行S.push(x)。如果x小于或等于堆栈M中的顶部元素,则我们还将执行M.push(x)。为了实现E.pop(),我们执行S.pop()。如果x等于堆栈M中的顶部元素,那么我们也为M.pop()。 E.findMin()是通过检查M的顶部来执行的。所有这些操作显然都是O(1)。

(b)该结果来自第7章中的一个定理,该定理表明排序必须花费Ω(N log N)个时间。清单中的O(N)个操作(包括deleteMin)足以进行排序。

3.26 可以实现三个堆栈,方法是一个堆栈从下向上生长,另一个堆栈从上向下生长,第三个堆栈在中间(某个方向)生长。如果第三个堆栈与其他两个堆栈中的任何一个发生冲突,则需要移动它。合理的策略是移动它,使其中心(移动时)位于其他两个堆栈的顶部之间的中间位置。

3.27 堆栈空间不会用完,因为只会堆叠49个调用。但是,运行时间是指数的,如第2章所示,因此该例程不会在合理的时间内终止。

3.28 这需要一个双向链接的列表,该列表具有指向头和尾的指针。实际上,可以通过重命名列表操作来使用列表来实现它。

template <typename Object>
class deque
{
public:
  deque() { l();}
  void push (Object obj) {l.push_front(obj);}
  Object pop (); {Object obj=l.front(); l.pop_front(); return obj;}
  void inject(Object obj); {l.push_back(obj);}
  Object eject(); {pop_back(obj);}
private:
  list<Object> l;
}; //

3.29

  Node * reverseList(Node *first)
{
  Node * currentPos, *nextPos, *previousPos;
  previousPos = NULL;
  currentPos = first;
  nextPos = first->next;
  while (nextPos != NULL)
   {
    currentPos -> next = previousPos;
    perviousPos = currentPos;
    currentPos = nextPos;
    nextPos = nextPos -> next;
   }
 currentPos->next = previousPos;
 return currentPos;
}

3.31

template <typename Object>
struct node
{
  node () { next = NULL;}
  node (Object obj) : data(obj) {}
  node (Object obj, node * ptr) : data(obj), next(ptr) {}
  Object data;
  node * next;
  };

template <typename Object>
class stack
{
 public:
  stack () { head = NULL;}
  ~stack() { while (head) pop();
 }
 
 void push(Object obj)
 {
  node<Object> * ptr = new node<Object>(obj, head);
  head= ptr;
}

Object top()
    {return (head->data); }

void pop()
  {
    node<Object> * ptr = head->next;
   delete head;
   head = ptr;
}

private:
node<Object> * head;
};

3.32

template <typename Object>
class queue
{
public:
 queue () { front = NULL; rear = NULL;}
 ~queue() { while (front) deque(); }

  void enque(Object obj)
  {
   node<Object> * ptr = new node<Object>(obj, NULL);
   if (rear)
     rear= rear->next = ptr;
   else
     front = rear = ptr;
  }

  Object deque()
  {
   Object temp = front->data;
   node<Object> * ptr = front;
   if (front->next == NULL) // only 1 node
      front = rear = NULL;
   else
    front = front->next;
  delete ptr;
  return temp;
 }

private:
  node<Object> * front;
  node<Object> * rear;
}; //

3.33

template <typename Object>
class queue
{
public:
queue(int s): maxSize(s), front(0), rear(0) {elements.resize(maxSize);}
queue () { maxSize = 100; front = 0;
rear = 0;elements.resize(maxSize);}
~queue() { while (front!=rear) deque(); }
void enque(Object obj)
{
  if (! full())
   {
    elements[rear] = obj;
    rear = (rear + 1) % maxSize;
    }
}

 Object deque()
 { 
 Object temp;
  if (!empty())
   {
    temp= elements[front];
    front = (front +1 ) % maxSize;
    return temp;
   }
 }

 bool empty() {return front == rear;}

 bool full() { return (rear + 1) % maxSize == front;}

private:
  int front, rear;
  int maxSize;
  vector<Object> elements ;
}; //

3.34(b)使用两个迭代器p和q,它们都最初在列表的开头。 一次前进p一步,一次前进q两步。 如果q到达末尾,则没有循环。 否则,p和q最终将在循环的中间相互追赶。

3.35(a)不能在固定时间内插入结尾(b)由于循环性,我们可以在固定时间内访问最前面的项目,因此可以正常工作。

3.36将下一个节点(即,被引用节点之后的节点)中的项目值复制到当前节点(即,被引用的节点)中。 然后删除下一个节点。

3.37(a)在位置p之后添加位置p上的节点的副本; 然后将位置p中存储的值更改为x。

(b)设置p-> data = p-> next-> data并设置p-> next = p-> next-> next。 然后删除p-> next。 请注意,尾节点保证始终有一个下一个节点。

你可能感兴趣的:(《数据结构与算法描述:c++实现》第3版第三章课后练习答案)