双向链表模板向量中的输入排序(C++)
Posted
技术标签:
【中文标题】双向链表模板向量中的输入排序(C++)【英文标题】:Sorting Input in Vector of Doubly Linked List Template (C++) 【发布时间】:2014-03-03 02:44:39 【问题描述】:我正在编写一个程序,该程序从一个 .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);
记录.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
【问题讨论】:
我一看到这个就停止阅读:delete this;
,然后是一堆被引用的成员变量。编译器错误只是冰山一角。我无法想象如果不对其中的一些进行单元测试,可以编写多少代码。
唯一不起作用的是 templatedoublylinkedlist.h 文件中的插入函数 我一路测试了其他所有内容,一切正常,甚至当我不调用该函数时它也可以工作插入。但是,当我在 main 中调用函数 insert 时,出现链接错误。
我不同意这一点。甚至读取循环也错误地使用std::istream::eof()
作为条件并且未能测试所有包含的提取是否成功。如果您想知道为什么您的 last 记录被插入 两次,这就是原因。我原来的评论是成立的。 delete this;
后跟 this
的引用成员会调用清晰呈现的未定义行为。
【参考方案1】:
很简单,复制构造函数没有在 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();
【讨论】:
没有定义是什么意思?我在我的班级中声明了它,然后它是在我的班级之外定义的第一个函数。我应该怎么做才能解决它? 好的,它已经定义但没有实现。它没有实体。以上是关于双向链表模板向量中的输入排序(C++)的主要内容,如果未能解决你的问题,请参考以下文章