#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。 请注意,尾节点保证始终有一个下一个节点。