双向链表模板向量中的输入排序(C ++)

时间:2014-03-03 02:44:40

标签: c++ list sorting vector insert

我正在编写一个程序,该文件从.txt文件中获取输入,该文件包含人名,姓氏,9位通用标识号(UIN)及其电话号码。我应该将此文件的输入读入双向链接列表的向量,其中向量的元素0对应于带有第一个字母“A”的姓氏的双向链接列表,元素1对应于最后一个双向链接列表第一个字母'B'的名称,依此类推。

我的代码可以从文件中读取数据并将其放在正确的列表中,但这些列表不会被排序。我应该在我的TemplateDoublyLinkedList中编写一个插入函数,将新元素放在列表中的正确位置,假设列表已排序,并在插入新元素后保持正确排序。

我的错误来自这个函数,但是我得到了非常模糊的链接器错误(这意味着我可能犯了一些愚蠢的错误),我无法弄清楚如何修复它。这是我的代码:

TemplateDoublyLinkedList.h

#include "Record.h"
#include <cstdlib>
#include <iostream>
#include <string>
#include <cstdio>
#include <sstream>
#pragma once
using namespace std;
template <typename T>
class DoublyLinkedList; // class declaration

// list node
template <typename T>
class DListNode {
private: T obj;
  DListNode<T> *prev, *next;
  friend class DoublyLinkedList<T>;
public:
  DListNode<T>(T object = T(), DListNode<T> *p = NULL, DListNode<T> *n = NULL)
    : obj(object), prev(p), next(n) {}
  T getElem() const { return obj; }
  DListNode<T> * getNext() const { return next; }
  DListNode<T> * getPrev() const { return prev; }
};

// doubly linked list
template <typename T>
class DoublyLinkedList {
protected: DListNode<T> header, trailer;
public:
  DoublyLinkedList<T>() : header(T()), trailer(T()) // constructor
  { header.next = &trailer; trailer.prev = &header; }
  DoublyLinkedList<T>(const DoublyLinkedList<T>& dll); // copy constructor
  ~DoublyLinkedList<T>(); // destructor
  DoublyLinkedList<T>& operator=(const DoublyLinkedList<T>& dll); // assignment operator
  // return the pointer to the first node
  DListNode<T> *getFirst() const { return header.next; } 
  // return the pointer to the trailer
  const DListNode<T> *getAfterLast() const { return &trailer; }
  // return if the list is empty
  bool isEmpty() const { return header.next == &trailer; }
  T first() const; // return the first object
  T last() const; // return the last object
  void insertFirst(T newobj); // insert to the first of the list
  T removeFirst(); // remove the first node
  void insertLast(T newobj); // insert to the last of the list
  T removeLast(); // remove the last node
  DListNode<T> *insert(T& newobj);
};
// output operator
template <typename T>
ostream& operator<<(ostream& out, const DoublyLinkedList<T>& dll);

// extend range_error from <stdexcept>
struct EmptyDLinkedListException : std::range_error {
  explicit EmptyDLinkedListException(char const* msg=NULL): range_error(msg) {}
};

// copy constructor
template <typename T>
DoublyLinkedList<T>::DoublyLinkedList(const DoublyLinkedList<T>& dll)
{
  header=T();
  trailer=T();
  header.next = &trailer; trailer.prev = &header;
  if (dll.isEmpty()) 
      return;

  DListNode<T>* current = dll.getFirst();
  while (current != dll.getAfterLast()) {
      T newObj = current->obj;
      insertLast(newObj);
      current = current->getNext();
  }

}
// assignment operator
template <typename T>
DoublyLinkedList<T>& DoublyLinkedList<T>::operator=(const DoublyLinkedList<T>& dll)
{
  delete this;

  header.next = &trailer; trailer.prev = &header;

  DListNode<T>* current = dll.getFirst();
  while (current != dll.getAfterLast()) {
      T newObj = current->obj;
      insertLast(newObj);
      current = current->getNext();
  }

  return *this;
}
// insert the object to the first of the linked list
template <typename T>
void DoublyLinkedList<T>::insertFirst(T newobj)
{ 
  DListNode<T> *newNode = new DListNode<T>(newobj, &header, header.next);
  header.next->prev = newNode;
  header.next = newNode;
}
// insert the object to the last of the linked list
template <typename T>
void DoublyLinkedList<T>::insertLast(T newobj)
{
  DListNode<T> *newNode = new DListNode<T>(newobj, trailer.prev,&trailer);
  trailer.prev->next = newNode;
  trailer.prev = newNode;
}
// remove the first object of the list
template <typename T>
T DoublyLinkedList<T>::removeFirst()
{ 
  if (isEmpty())
    throw EmptyDLinkedListException("Empty Doubly Linked List");
  DListNode<T> *node = header.next;
  node->next->prev = &header;
  header.next = node->next;
  T obj = node->obj;
  delete node;
  return obj;
}
// remove the last object of the list
template <typename T>
T DoublyLinkedList<T>::removeLast()
{
  if (isEmpty())
    throw EmptyDLinkedListException("Empty Doubly Linked List");
  DListNode<T> *node = trailer.prev;
  node->prev->next = &trailer;
  trailer.prev = node->prev;
  T obj = node->obj;
  delete node;
  return obj;
}
// destructor
template <typename T>
DoublyLinkedList<T>::~DoublyLinkedList()
{
  DListNode<T> *prev_node, *node = header.next;
  while (node != &trailer) {
    prev_node = node;
    node = node->next;
    delete prev_node;
  }
  header.next = &trailer;
  trailer.prev = &header;
}
// return the first object
template <typename T>
T DoublyLinkedList<T>::first() const
{ 
  if (isEmpty())
    throw EmptyDLinkedListException("Empty Doubly Linked List");
  return header.next->obj;
}
// return the last object
template <typename T>
T DoublyLinkedList<T>::last() const
{
  if (isEmpty())
    throw EmptyDLinkedListException("Empty Doubly Linked List");
  return trailer.prev->obj;
}
// return the list length
template <typename T>
int DoublyLinkedListLength(DoublyLinkedList<T>& dll) {
  DListNode<T> *current = dll.getFirst();
  int count = 0;
  while(current != dll.getAfterLast()) {
    count++;
    current = current->getNext(); //iterate
  }
  return count;
}
// output operator
template <typename T>
ostream& operator<<(ostream& out, const DoublyLinkedList<T>& dll) {
  DListNode<T> *current = dll.getFirst();
  while (current != dll.getAfterLast()) {
      out << current->getElem() << '\n';
      current = current->getNext();
  }
  return out;
}

template <typename T>
DListNode<T> *insert(T& obj) {
    DListNode<T> *current = this->getFirst();
    while (obj < current->obj) {
        current = current->getNext();
    }

    DListNode<T> *newNode = new DListNode<T>(obj, current->prev, current);
    curren->prev = newNode;
    added->prev->next = added;
    return newNode;
}

Record.h(适用于我的ADT的班级,包含每个“人”及其姓名,UIN和电话号码)

#include <iostream>
#include <cstdlib>
#include <string>
#pragma once
using namespace std;

class Record {
private:
    string lastName, firstName, universalIdentificationNumber, phoneNumber;
public:
    Record(string last = "EMPTY", string first = "EMPTY", string UIN = "EMPTY", string phone = "EMPTY") : 
        lastName(last), firstName(first), universalIdentificationNumber(UIN), phoneNumber(phone) {}
    bool operator < (const Record& r);

    string getLast() const { return lastName; }
    string getFirst() const { return firstName; }
    string getUIN() const { return universalIdentificationNumber; }
    string getPhone() const { return phoneNumber; }

    void setLast(string s) { lastName = s; }
    void setFirst(string s) { firstName = s; }
    void setUIN(string s) { universalIdentificationNumber = s; }
    void setPhone(string s) { phoneNumber = s; }
};

ostream& operator<<(ostream& out, const Record& r);

Record.cpp

#include "Record.h"
#include "TemplateDoublyLinkedList.h"
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;

bool Record::operator < (const Record& r) {
    if (getLast().compare(r.getLast()) < 0) 
        return true;
    if (getLast().compare(r.getLast()) >0)
        return false;
    if (getLast().compare(r.getLast()) == 0) {
        if (getFirst().compare(r.getFirst()) < 0)
            return true;
        if (getFirst().compare(r.getFirst()) > 0)
            return false;
        if (getFirst().compare(r.getFirst()) == 0) {
            if (getUIN().compare(r.getUIN()) < 0) 
                return true;
            if (getUIN().compare(r.getUIN()) > 0)
                return false;
            if (getUIN().compare(r.getUIN()) == 0) {
                if (getPhone().compare(r.getPhone()) < 0)
                    return true;
                if (getPhone().compare(r.getPhone()) > 0)
                    return false;
                if (getPhone().compare(r.getPhone()) == 0)
                    return true;
            }
        }
    }
    return false;
}

ostream& operator<<(ostream& out, const Record& r) {
    out << "Last Name: " << r.getLast() << '\n'
        << "First Name: " << r.getFirst() << '\n'
        << "UIN: " << r.getUIN() << '\n'
        << "Phone Number: " << r.getPhone() << '\n';

    return out;
}

Main.cpp的

#include "Record.h"
#include "TemplateDoublyLinkedList.h"
#include <cstdlib>
#include <string>
#include <iostream>
#include <cstdio>
#include <sstream>
#include <vector>
#include <fstream>
using namespace std;

void display(vector<DoublyLinkedList<Record>>& v) {
    for (int i=0; i<v.size(); ++i) {
        cout << v[i];
    }
}

int firstLetterSort (string s) {
    char firstLetter = s.at(0);
    int location;

    switch (firstLetter) {
    case 'a':
    case 'A':
        location = 0;
        break;
    case 'b':
    case 'B':
        location = 1;
        break;
    case 'c':
    case 'C':
        location = 2;
        break;
    case 'd':
    case 'D':
        location = 3;
        break;
    case 'e':
    case 'E':
        location = 4;
        break;
    case 'f':
    case 'F':
        location = 5;
        break;
    case 'g':
    case 'G':
        location = 6;
        break;
    case 'h':
    case 'H':
        location = 7;
        break;
    case 'i':
    case 'I':
        location = 8;
        break;
    case 'j':
    case 'J':
        location = 9;
        break;
    case 'k':
    case 'K':
        location = 10;
        break;
    case 'l':
    case 'L':
        location = 11;
        break;
    case 'm':
    case 'M':
        location = 12;
        break;
    case 'n':
    case 'N':
        location = 13;
        break;
    case 'o':
    case 'O':
        location = 14;
        break;
    case 'p':
    case 'P':
        location = 15;
        break;
    case 'q':
    case 'Q':
        location = 16;
        break;
    case 'r':
    case 'R':
        location = 17;
        break;
    case 's':
    case 'S':
        location = 18;
        break;
    case 't':
    case 'T':
        location = 19;
        break;
    case 'u':
    case 'U':
        location = 20;
        break;
    case 'v':
    case 'V':
        location = 21;
        break;
    case 'w':
    case 'W':
        location = 22;
        break;
    case 'x':
    case 'X':
        location = 23;
        break;
    case 'y':
    case 'Y':
        location = 24;
        break;
    case 'z':
    case 'Z':
        location = 25;
    }
    return location;
}

int main() {
    vector<DoublyLinkedList<Record>> phoneBook(26);
    const string phoneBookFile = "PhoneBook";
    string searchedLast, searchedFirst, searchedUIN;
    int firstLetter;

    ifstream ist(phoneBookFile.c_str());
    ist.open("PhoneBook.txt");
    if (ist.is_open()) {
        while (!ist.eof()) {
            Record nextRecord;
            string first, last, UIN, phone, empty;

            getline(ist, last);
            getline(ist, first);
            getline(ist, UIN);
            getline(ist, phone);
            getline(ist, empty);

            nextRecord.setLast(last);
            nextRecord.setFirst(first);
            nextRecord.setUIN(UIN);
            nextRecord.setPhone(phone);

            int location = firstLetterSort(last);
            phoneBook[location].insert(nextRecord);
        }
    }

    display(phoneBook);
}

我的错误由我的编译器输出:

1>Main.obj : error LNK2019: unresolved external symbol "public: class DListNode<class Record> * __thiscall DoublyLinkedList<class Record>::insert(class Record &)" (?insert@?$DoublyLinkedList@VRecord@@@@QAEPAV?$DListNode@VRecord@@@@AAVRecord@@@Z) referenced in function _main
1>C:\Users\Snyperanihilatr\Documents\Visual Studio 2012\Projects\Phonebook\Debug\Phonebook.exe : fatal error LNK1120: 1 unresolved externals

1 个答案:

答案 0 :(得分:0)

简单,复制构造函数在DoubleLinkedList中没有定义主体。这通常是为了防止它被使用。正如您在下面看到的,复制构造函数没有正文,这就是链接器无法找到它的原因。

DoublyLinkedList<T>(const DoublyLinkedList<T>& dll); // copy constructor

您需要复制构造函数的原因是矢量模板使用它。您可以通过存储指向DoubleLinkedList而不是对象的指针来防止这种情况。

vector<DoublyLinkedList<Record>*> phoneBook(26);
for(char c='a' ; c<='z'; c++) 
{
    phoneBook[c] = new DoubleLinkedList();
}