问题
I am trying to, without using a ListIterator, define and implement a new operation called insert_back which takes a single template Object and inserts the Object at the end of the list. Without changing the meaning of this operation or any other, I need to modify the representation of a List and alter whatever methods are necessary to make insert_back run in constant time: O(1).
I am totally stumped at implementing this.
I want to make another menu option named INSERTBACK that will insert a new object at the end of the list
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
IMPLEMENTATION LISTMENU.CPP
// Menu.cpp : Defines the entry point for the console application. //
#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 );
}
EDIT: Added 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
回答1:
The linked list you currently have defined is called a single-linked list, as you have a single pointer (next), and you only store a pointer to the head of the list. Add to your List container an additional pointer called tail, and point it at the last element. You will need to adjust your List methods to properly assign tail and address it.
Another approach could be to convert your list to a double linked list with (next, previous) pointers, and you could then maintain head->previous to point to the tail of your list (a double-linked, circular list).
A third way would be to make your single-linked list circular, but store pointers as XOR of the previous and next pointer (see: http://en.wikipedia.org/wiki/XOR_linked_list).
Here are examples of some changes you need to make to add a 'tail' member to your List, and use it to create an insert_back operation.
You list implementation seems to add a new node even to an empty list.
Add the member to your List.h definition,
void insert_back( const Object& data );
ListNode<Object>* head;
ListNode<Object>* tail; //add a tail
Your list implementation creates a ListNode even on an empty list. Not sure you intend to do that. Anyway, in your constructor, initialize the tail (which is usually NULL, maybe you want to init to the wasted node you place in the list).
List<Object>::List() {
head = new ListNode<Object>;
tail = NULL; //or = head
}
You also have list assignment, which is fine except that what do you do with the node(s) in the list you are assigning to (you don't call makeEmpty), but you will need to do something sane with tail here -- but since you are just assigning, I'll set tail=NULL, to remind you do do something sane,
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
}
When you makeEmpty, your tail will need to be emptied,
void List<Object>::makeEmpty() {
while (!isEmpty()) {
remove( first().retrieve() );
}
tail = NULL;
}
Your existing insert methods need to initialize tail when the list is empty, left as an exercise,
You will need an insert_back method, which only needs to point tail->next at the new node (if there is a tail), and then set tail to the new node,
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);
}
}
回答2:
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;
}
The above code assumes the following:
- You have a ListNode object defined in your
ListNode
class calledtailPointer
- tailPointer points to the last element in the
ListNode
linkedList and is infact a pointer as the name suggests
来源:https://stackoverflow.com/questions/19505891/singly-list-insert-to-end-of-list