我试图在不使用ListIterator的情况下,定义并实现一个名为insert_back的新操作,该操作采用单个模板Object并在列表末尾插入Object。在不改变此操作或任何其他操作的含义的情况下,我需要修改List的表示形式并更改使insert_back在常量时间运行所需的任何方法:O(1)。
我完全没有意识到这一点。
我想创建另一个名为INSERTBACK的菜单选项,它将在列表的末尾插入一个新对象
LIST.H
#ifndef LIST_H
#define LIST_H
#include <iostream>
#include "ListNode.h"
#include "ListIterator.h"
namespace cs20 {
template <class Object>
class List {
public:
List();
List( const List& rhs );
~List();
bool isEmpty() const;
bool isIncreasing() const;
void makeEmpty();
ListIterator<Object> zeroth() const;
ListIterator<Object> first() const;
void insert( const Object& data,
const ListIterator<Object> &iter );
void insert( const Object& data );
void insert_back( const Object& data );
ListIterator<Object> findPrevious( const Object& data ) const;
void remove( const Object& data );
const List& operator =( const List& rhs );
const List& operator <<( const List& rhs );
private:
ListNode<Object> * head;
ListNode<Object> * tail;
};
}
#endif
LIST.CPP
#ifndef LIST_CPP
#define LIST_CPP
#include "List.h"
namespace cs20 {
template <class Object>
List<Object>::List() {
head = new ListNode<Object>;
tail->nextIsNull();
}
template <class Object>
List<Object>::List( const List<Object>& rhs ) {
head = new ListNode<Object>;
tail->nextIsNull();
*this = rhs;
}
template <class Object>
List<Object>::~List() {
makeEmpty();
delete head;
}
template <class Object>
bool List<Object>::isEmpty() const {
return( head->nextIsNull() );
}
template <class Object>
void List<Object>::makeEmpty() {
while (!isEmpty()) {
remove( first().retrieve() );
}
tail = NULL;
}
template <class Object>
ListIterator<Object> List<Object>::zeroth() const {
return( ListIterator<Object>( head ) );
}
template <class Object>
ListIterator<Object> List<Object>::first() const {
return( ListIterator<Object>( head->getNext() ) );
}
template <class Object>
void List<Object>::insert( const Object& data,
const ListIterator<Object> &iter ) {
if (iter.isValid()) {
ListNode<Object>* newnode = new ListNode<Object>( data, iter.current->getNext() );
iter.current->setNext( newnode );
}
}
template <class Object>
void List<Object>::insert( const Object& data ) {
ListNode<Object>* newnode = new ListNode<Object>( data, head->getNext() );
head->setNext( newnode );
}
template <class Object>
void List<Object>::insert_back( const Object& data ) {
ListNode<Object>* newnode = new ListNode<Object>( data, tail->getNext() );
if( tail != NULL )
{
tail->setNext( newnode );
}
tail = newnode;
if( head->getNext() == NULL ) {
head->setNext(newnode);
}
}
template <class Object>
ListIterator<Object> List<Object>::findPrevious( const Object& data ) const {
ListNode<Object>* node = head;
while( node->getNext() != NULL && node->getNext()->getElement() != data ) {
node = node->getNext();
}
if (node->getNext() == NULL) {
node = NULL;
}
return ListIterator<Object>( node );
}
template <class Object>
bool List<Object>::isIncreasing() const {
ListNode<Object>* node= head;
while (node->getNext() != NULL)
{
if (node->getNext()->getElement() <= node->getElement())
return false;
node = node->getNext();
}
return true;
}
template <class Object>
void List<Object>::remove( const Object& data ) {
ListIterator<Object> iter = findPrevious( data );
if (iter.isValid()) {
ListNode<Object>* node = findPrevious( data ).current;
if (node->getNext() != NULL) {
ListNode<Object> *oldNode = node->getNext();
node->setNext( node->getNext()->getNext() ); // Skip oldNode
delete oldNode;
}
}
}
// Deep copy of linked list
template <class Object>
const List<Object>& List<Object>::operator =( const List<Object>& rhs ) {
if (this != &rhs) {
makeEmpty();
ListIterator<Object> rightiter = rhs.first( );
ListIterator<Object> myiterator = zeroth();
while( rightiter.isValid() ) {
insert( rightiter.retrieve(), myiterator );
rightiter.advance();
myiterator.advance();
}
}
return( *this );
}
}
#endif
实施 LISTMENU.CPP
// Menu.cpp:定义控制台应用程序的入口点。 //
#include <iostream>
#include "List.h"
#include "ListNode.h"
#include "ListIterator.h"
#include "List.cpp"
#include "ListNode.cpp"
#include "ListIterator.cpp"
using namespace std;
using namespace cs20;
enum CHOICE {MAKEEMPTY, REMOVE, ISEMPTY, FINDPREVIOUS, INSERT, QUIT, PRINT };
CHOICE menu();
void printList( const List<int>& l );
int main(int argc, char* argv[]) {
int value;
List<int> list;
ListIterator<int> iter;
CHOICE choice;
do {
choice = menu();
switch( choice ) {
case MAKEEMPTY:
list.makeEmpty();
break;
case ISEMPTY:
if (list.isEmpty()) {
cout << "list is empty" << endl;
}
else {
cout << "list is not empty" << endl;
}
break;
case REMOVE:
cout << "Please provide int to remove: ";
cin >> value;
list.remove( value );
break;
case INSERT:
cout << "Please provide int to insert: ";
cin >> value;
list.insert( value );
break;
case FINDPREVIOUS:
cout << "Please provide int to find: ";
cin >> value;
iter = list.findPrevious( value );
if (iter.isValid()) {
cout << "previous element = " << iter.retrieve() << endl;
}
else {
cout << "data element was not found!" << endl;
}
break;
case PRINT:
printList( list );
break;
case QUIT:
break;
}
} while (choice != QUIT);
return( 0 );
}
int sample() {
cout << "Forming Lists" << endl;
int one = 1, two = 2;
List<int> l1 = List<int>();
List<int> l2 = List<int>();
l1.insert( one );
l1.insert( two );
cout << "print l1" << endl;
printList( l1 );
cout << "l2 = l1" << endl;
l2 = l1;
cout << "print l2" << endl;
printList( l2 );
cout << "l1.remove(one)" << endl;
l1.remove( one );
cout << "print l1" << endl;
printList( l1 );
cout << "print l2" << endl;
printList( l2 );
cout << "findPrevious 1 in l2" << endl;
ListIterator<int> iter = l2.findPrevious( one );
if (iter.isValid()) {
cout << "--iter valid" << endl;
cout << iter.retrieve() << endl;
}
else {
cout << "--iter not valid" << endl;
}
cout << "findPrevious 2 in l2" << endl;
iter = l2.findPrevious( two );
if (iter.isValid()) {
cout << "--iter valid" << endl;
cout << iter.retrieve() << endl;
}
else {
cout << "--iter not valid" << endl;
}
cout << "findPrevious 1 in l1" << endl;
iter = l1.findPrevious( one );
if (iter.isValid()) {
cout << "--iter valid" << endl;
cout << iter.retrieve() << endl;
}
else {
cout << "--iter not valid" << endl;
}
cout << "findPrevious 2 in l1" << endl;
iter = l1.findPrevious( two );
if (iter.isValid()) {
cout << "--iter valid" << endl;
cout << iter.retrieve() << endl;
}
else {
cout << "--iter not valid" << endl;
}
cout << "print l1" << endl;
printList( l1 );
// you can remove whatever you want, whether it exists or not
cout << "l1.remove(one)" << endl;
l1.remove( one );
cout << "print l1" << endl;
printList( l1 );
return( 0 );
}
void printList( const List<int>& l ) {
if (l.isEmpty())
cout << "Empty list" << endl;
else {
ListIterator<int> iter = l.first();
while (iter.isValid()) {
cout << iter.retrieve() << " -> ";
iter.advance();
}
cout << "NULL";
cout << endl;
}
}
CHOICE menu() {
char choice;
CHOICE result;
cout << "(M)akeEmpty I(s)Empty (R)emove (I)nsert (F)indPrevious (P)rint (Q)uit: " << endl;
cin >> choice;
switch( choice ) {
case 'M':
case 'm':
result = MAKEEMPTY;
break;
case 'S':
case 's':
result = ISEMPTY;
break;
case 'R':
case 'r':
result = REMOVE;
break;
case 'I':
case 'i':
result = INSERT;
break;
case 'F':
case 'f':
result = FINDPREVIOUS;
break;
case 'Q':
case 'q':
result = QUIT;
break;
case 'P':
case 'p':
result = PRINT;
break;
}
return( result );
}
编辑:添加了ListNode.cpp 的 ListNode.CPP
#ifndef LISTNODE_CPP
#define LISTNODE_CPP
#include "ListNode.h"
namespace cs20 {
template <class Object>
ListNode<Object>::ListNode( const Object& theElement,
ListNode<Object> * node ) {
element = theElement;
next = node;
}
template <class Object>
bool ListNode<Object>::nextIsNull() const {
return( next == NULL );
}
template <class Object>
const Object& ListNode<Object>::getElement() const {
return( element );
}
template <class Object>
ListNode<Object>* ListNode<Object>::getNext() const {
return( next );
}
template <class Object>
void ListNode<Object>::setNext( ListNode<Object> * node ) {
next = node;
}
}
#endif
答案 0 :(得分:5)
您当前定义的链接列表称为单链接列表,因为您有一个指针(下一个),并且您只存储指向列表头部的指针。将名为tail的附加指针添加到List容器中,并将其指向最后一个元素。您需要调整List方法以正确分配尾部并对其进行寻址。
另一种方法可能是将列表转换为带有(next,previous)指针的双链表,然后你可以保持head-&gt; previous指向列表的尾部(双链接,循环列表) )。
第三种方法是使单链表循环,但将指针存储为上一个和下一个指针的XOR(参见:http://en.wikipedia.org/wiki/XOR_linked_list)。
以下是将“尾部”成员添加到List中所需进行的一些更改示例,并使用它来创建insert_back操作。
列表实现似乎甚至将新节点添加到空列表中。
将成员添加到List.h定义
void insert_back( const Object& data );
ListNode<Object>* head;
ListNode<Object>* tail; //add a tail
即使在空列表中,您的列表实现也会创建一个ListNode。不确定你打算这样做。无论如何,在你的构造函数中,初始化尾部(通常是NULL,也许你想初始化到你放在列表中的浪费节点)。
List<Object>::List() {
head = new ListNode<Object>;
tail = NULL; //or = head
}
你也有列表分配,这很好,除了你用你所分配的列表中的节点做什么(你不调用makeEmpty),但是你需要做一些理智的尾巴这里 - 但既然你只是分配,我会设置tail = NULL,提醒你做一些理智的事情,
List<Object>::List( const List<Object>& rhs ) {
head = new ListNode<Object>;
tail = NULL; //or = head
*this = rhs; //the list node you just assigned is lost here
}
当你做空时,你的尾巴需要被清空,
void List<Object>::makeEmpty() {
while (!isEmpty()) {
remove( first().retrieve() );
}
tail = NULL;
}
当列表为空时,您的现有插入方法需要初始化尾部,留作练习
你需要一个insert_back方法,只需要在新节点指向tail-&gt; next(如果有尾部),然后将tail设置为新节点,
template <class Object>
void List<Object>::insert_back( const Object& data ) {
// insert after the tail node
ListNode<Object>* newnode = new ListNode<Object>( data, tail->getNext() );
if( tail != NULL ) //not empty, point tail->next at newnode
{
tail->setNext( newnode );
}
tail = newnode;
if( head->getNext() == NULL ) //empty, newnode is head and tail
{
head->setNext(newnode);
}
}
答案 1 :(得分:0)
template <typename Object>
void List<object>::insert_back(const Object& data) {
ListNode<Object> *newListIter = new ListNode<Object>(data, NULL);
head->tailPointer->setNext(newListIter);
head->tailPointer = newListIter;
}
以上代码假设如下:
ListNode
类中定义了一个名为tailPointer
ListNode
linkedList中的最后一个元素,并且顾名思义就是指针