When I run my program, it works as intended, except the items in the list have no spaces between them when the displayList() function is called. I have 3 files. The main cpp file is ShoppingList.cpp. Then I have two other files for the linked list classification and implementation.
//ShoppingList.cpp
//Michael Hery
//COP 2001
//11/9/17
//Shopping List
#include <iostream>
#include <string>
#include "strList.h"
#include "strlist.cpp"
using namespace std;
int main()
{
//Define a NumberList object
StrList list;
string item;
string delItem;
int menuSelection;
//Ask the user how many items to
//put in the list
cout << "How many items would you like to put it the list? >> ";
cin >> menuSelection;
while (menuSelection < 1)
{
cout << "Please enter a valid number (greater than 0) >> ";
cin >> menuSelection;
}
for (int i = 0; i < menuSelection; i++)
{
cout << "Please enter item " << i + 1 << ": ";
cin >> item;
list.appendNode(item);
}
list.displayList();
cout << "Which item do you wish to delete from the list? >> ";
cin >> delItem;
while (delItem == "")
{
cout << "Please enter a valid item >> ";
cin >> delItem;
}
list.deleteNode(delItem);
list.displayList();
//Wait for user input to exit program
system("PAUSE");
return 0;
}
//strList.h
#ifndef STRLIST_H
#define STRLIST_H
#include <iostream>
#include <string>
namespace
{
class StrList
{
private:
struct ListNode
{
std::string value;
struct ListNode *next;
};
ListNode *head;
public:
//Constructor
StrList()
{
head = nullptr;
}
//Destructor
~StrList();
//Linked List Operations
void appendNode(std::string item);
void insertNode(std::string item);
void deleteNode(std::string item);
void displayList() const;
};
}
#endif
//strList.cpp
#ifndef STRLIST_CPP
#define STRLIST_CPP
#include <iostream>
#include <string>
#include "strList.h"
void StrList::appendNode(std::string item)
{
ListNode *newNode;
ListNode *nodePtr;
//Allocate a new node and store item there
newNode = new ListNode;
newNode->value = item;
newNode->next = nullptr;
//If there are no nodes in the list
//make newNode the first node
if (!head)
head = newNode;
else //Otherwise, insert newNode at the end
{
//Initialize nodePtr to head of the list
nodePtr = head;
//Find the last node in the list
while (nodePtr->next)
nodePtr = nodePtr->next;
//Insert newNode as the last node
nodePtr->next = newNode;
}
}
void StrList::insertNode(std::string item)
{
ListNode *newNode;
ListNode *nodePtr;
ListNode *previousNode = nullptr;
//Allocate a new node and store num there
newNode = new ListNode;
newNode->value = item;
//If there are no nodes in the list
//make newNode the first node
if (!head)
{
head = newNode;
newNode->next = nullptr;
}
else //Otherwise, insert newNode
{
//Position nodePtr at the head of list
nodePtr = head;
//Initialize previousNode to nullPtr
previousNode = nullptr;
//Skip all nodes whose values is less than num
while (nodePtr != nullptr && nodePtr->value < item)
{
previousNode = nodePtr;
nodePtr = nodePtr->next;
}
//If the new node is to be the 1st in the list,
//insert it before all the other nodes
if (previousNode == nullptr)
{
head = newNode;
newNode->next = nodePtr;
}
else //Otherwise insert after the previous node
{
previousNode->next = newNode;
newNode->next = nodePtr;
}
}
}
void StrList::deleteNode(std::string item)
{
ListNode *nodePtr; //To traverse the list
ListNode *previousNode = nullptr; //To point to the previous node
//If the list is empty, do nothing
if (!head)
return;
//Determine if the first node is the one
if (head->value == item)
{
nodePtr = head->next;
delete head;
head = nodePtr;
}
else
{
//Initialize nodePtr to head of list
nodePtr = head;
//Skip all nodes whose value member is
//not equal to num
while (nodePtr != nullptr && nodePtr->value != item)
{
previousNode = nodePtr;
nodePtr = nodePtr->next;
}
//If nodePtr is not at the end of the list,
//link the previous node to the node after
//nodePtr, then delete nodePtr
if (nodePtr)
{
previousNode->next = nodePtr->next;
delete nodePtr;
}
}
}
StrList::~StrList()
{
ListNode *nodePtr; //To traverse the list
ListNode *nextNode; //To point to the next node
//Position nodePtr at the head of the list
nodePtr = head;
//While nodePtr is not at the end of the list
while (nodePtr != nullptr)
{
//Save a pointer to the next node
nextNode = nodePtr->next;
//Delete the current node
delete nodePtr;
//Position nodePtr at the next node
nodePtr = nextNode;
}
}
void StrList::displayList() const
{
ListNode *display;
display = head;
std::cout << "**********************************" << std::endl;
std::cout << "**** Your Shopping List ****" << std::endl;
std::cout << "**********************************" << std::endl;
while (display)
{
std::cout << display->value;
display = display->next;
}
}
#endif
The problem lies in the displayList(); function towards the end of the file.
Add a separator for between your values.
char const* sep = "";
while (display)
{
std::cout << sep << display->value;
sep = " ";
display = display->next;
}
Related
when i run this program, it gives me a segmentation fault after runs the printlist function. I'm not sure why the program is completely skipping over the input function. I set the input variable to a number in the function already so it couldn't be some left over value causing it right?
class function implementation:
#include <iostream>
#include "OrderedList.h"
using namespace std;
OrderedList::OrderedList() {
head = nullptr;
}
OrderedList::OrderedList(const OrderedList& a) {
ListNode * newNode;
ListNode * copyNode;
if(!a.head){
return;
}else {
copyNode = a.head;
newNode = new ListNode;
this->head = newNode;
head->value = copyNode->value;
copyNode = copyNode->next;
newNode->next = nullptr;
}
}
OrderedList :: ~OrderedList() {
ListNode * nodePtr;
ListNode * nextNode;
nodePtr = head;
while(nodePtr != nullptr){
nextNode = nodePtr->next;
delete nodePtr;
nodePtr = nextNode;
}
}
void OrderedList :: insert() {
int num = 0;
while(num){
cout << "Type a number for insertion (type x to stop): ";
cin >> num;
ListNode * newNode;
ListNode * prev;
ListNode * nodePtr;
newNode = new ListNode;
newNode->value = num;
newNode->next = nullptr;
if(!head){
head = newNode;
newNode->next = nullptr;
}else {
nodePtr = head;
prev = nullptr;
while(nodePtr != nullptr && nodePtr->value < num){
prev = nodePtr;
nodePtr = nodePtr->next;
}
if(prev == nullptr){
head = newNode;
newNode->next = nodePtr;
}else {
prev->next = newNode;
newNode->next = nodePtr;
}
}
}
}
void OrderedList :: printList() {
ListNode * nodePtr;
nodePtr = head;
while(nodePtr != nullptr){
cout << nodePtr->value << " ";
nodePtr = nodePtr->next;
}
cout << endl;
}
driver program:
#include <iostream>
#include <iomanip>
#include "OrderedList.h"
using namespace std;
int main() {
OrderedList A;
cout << "Asking user to type and create listA..." << endl;
A.insert();
cout << "listA is: " << setw(20) << endl;
A.printList();
OrderedList B(A);
cout << "listB is copied from listA: ";
B.printList();
}
the output looks like this by the way:
Asking user to type and create listA...
listA is:
Segmentation fault (core dumped)
When you run the code, it won't print anything unless when you run it with 3 appends. Why is that? Inside the code, I added cout statement to check if it ran and when I appended 4 things to the linked list, it only ran once in the append function. But when I ran it with only 3 things appended to the list, it displayed the cout statement 3x.
main.cpp:
#include <iostream>
#include "node.h"
using namespace std;
int main()
{
LL list;
list.append("jack","2");
list.append("jack","1");
list.append("jack","3");
list.append("jack","4");
//list.insertatBegin("notjack","0");
list.print();
}
node.cpp:
#include <iostream>
using namespace std;
#include "node.h"
LL::LL()
{
head = nullptr;
}
void LL::append(string pName,string phone)
{
Node *nodePtr;
if (head == nullptr)
{
head = new Node;
head->name = pName;
head->phoneNumber = phone;
head->next = nullptr;
}
else
{
nodePtr = head;
while(nodePtr->next !=nullptr)
{
nodePtr = nodePtr->next;
}
nodePtr->next = new Node;
nodePtr->next->name = pName;
nodePtr->next->phoneNumber = phone;
nodePtr->next->next = nullptr;
}
}
void LL::print()
{
//cout << "ran" <<endl;
Node *nodePtr;
nodePtr = head;
while (nodePtr == nullptr)
{
cout << nodePtr ->name << " " << nodePtr->phoneNumber <<endl;
nodePtr = nodePtr->next;
}
}
node.h:
#ifndef NODE_H
#define NODE_H
#include <iostream>
using namespace std;
class Node
{
public:
string name; //data
string phoneNumber;
Node* next; //pointer to next
};
class LL
{
private:
Node* head; // list header
public:
LL();
void append(string pName,string phone);
void insertatBegin(string pName,string phone);
void print();
};
#endif
There are 2 problems with your code:
append() has undefined behavior, because newNode is uninitialized. Its value is indeterminate, causing it to point at random memory. You are not pointing it to a valid new'ed instance of Node before trying to populate it.
print() is not looping through the list at all.
Try this:
void LL::append(string pName,string phone)
{
Node *newNode = new Node; // <-- notice 'new'!
// these assignments really should be handled by a constructor...
newNode->name = pName;
newNode->phoneNumber = phone;
newNode->next = nullptr;
if (head == nullptr)
// better: if (!head)
{
cout << "it ran" <<endl;
head = newNode;
}
else
{
cout << "it ran2" <<endl;
Node *nodePtr = head;
while (nodePtr->next != nullptr)
// better: while (nodePtr->next)
{
nodePtr = nodePtr->next;
}
nodePtr->next = newNode;
}
}
void LL::print()
{
//cout << "ran" <<endl;
Node *nodePtr = head;
while (nodePtr != nullptr) // <-- '!=', not '=='
// better: while (nodePtr)
{
cout << nodePtr ->name << " " << nodePtr->phoneNumber << endl;
nodePtr = nodePtr->next;
}
}
That said, append() can be simplified a bit more:
class Node
{
public:
string name; //data
string phoneNumber;
Node* next = nullptr; //pointer to next
Node(string pName, string phone) : name(pName), phoneNumber(phone) {}
};
void LL::append(string pName,string phone)
{
Node *newNode = new Node(pName, phone);
Node **nodePtr = &head;
while (*nodePtr)
{
nodePtr = &((*nodePtr)->next);
}
*nodePtr = newNode;
// Alternatively:
/*
Node **nodePtr = &head;
while (*nodePtr)
{
nodePtr = &((*nodePtr)->next);
}
*nodePtr = new Node(pName, phone);
*/
}
For starters your newNode pointer does not point to anything and you are assigning to uninitialized variables name, phonenumber and next.
Node *nodePtr;
newNode->name = pName;
newNode->phoneNumber = phone;
newNode->next = nullptr;
Compiles fine but when executed I get segmentation fault (core dumped) error. I've tested each function individually and the add function is the only one giving me this error. Add function is supposed to add the value to the head of the linked list. When running the code, values get added to the list correctly and I can display the list, but the error follows shortly after.
//Homework 11
//Linked List
#include <iostream>
using namespace std;
//Declaring class and Linked List.
class NumberList
{
private:
struct ListNode
{
double value;
struct ListNode *next;
};
ListNode *head;
public:
NumberList()
{ head = NULL;}
~NumberList()
{
ListNode *nodePtr;
ListNode *nextNode;
nodePtr = head;
while (nodePtr != NULL)
{
nextNode = nodePtr->next;
delete nodePtr;
nodePtr = nextNode;
}
}
//Function inserting node at the head.
void add(double x)
{
ListNode *newNode;
ListNode *nodePtr;
ListNode *previousNode = NULL;
newNode = new ListNode;
newNode->value = x;
if (!head)
{
head = newNode;
newNode -> next = NULL;
}
else
{
nodePtr = head;
previousNode = NULL;
}
if (previousNode == NULL)
{
head = newNode;
newNode->next = nodePtr;
}
}
//Function to find matching values.
bool isMember(double x)
{
int pos = 0;
bool flag = false;
if (head == NULL)
{
cout << "List is Empty" << endl;
return flag;
}
ListNode *nodePtr;
nodePtr = head;
while (nodePtr != NULL)
{
pos++;
if (nodePtr->value == x)
{
flag = true;
cout << x << " was found at position " << pos << endl;
}
nodePtr = nodePtr->next;
}
if (!flag)
{
cout << x << " not found in the list." << endl;
}
return flag;
}
//Function to display linked list values.
void display() const
{
ListNode *nodePtr;
if (head == NULL)
{
cout << "List is empty." << endl;
return;
}
nodePtr = head;
cout << "The list goes: " << endl;
while (nodePtr != NULL)
{
cout << nodePtr->value << endl;
nodePtr = nodePtr->next;
}
cout << "End" << endl;
}
//Function to delete a selected value in the list.
void deletNodeAll(double x1)
{
ListNode *nodePtr;
ListNode *previousNode;
if (!head)
return;
if (head->value == x1)
{
nodePtr = head->next;
delete head;
head = nodePtr;
}
else
{
nodePtr = head;
while ( nodePtr != NULL && nodePtr->value != x1)
{
previousNode = nodePtr;
nodePtr = nodePtr->next;
}
if (nodePtr)
{
previousNode->next = nodePtr->next;
delete nodePtr;
}
}
}
};
int main()
{
NumberList Z;
Z.add(3);
Z.add(4);
Z.add(2);
Z.add(5);
Z.add(7);
Z.add(4);
Z.add(7);
Z.add(5);
Z.add(2);
Z.display();
Z.isMember(2);
Z.deletNodeAll(2);
Z.display();
return 0;
}
your add() method causes segmentation fault because for first node you should update the head and head->next and return but you didn't.
if (!head) {
head = newNode;
newNode -> next = NULL;
return ;/* do this else this again check previousNode == NULL also
which is not needed 1st time */
}
Also deletNodeAll() deletes only first occurrence of number you are passing, there is a bug in logic,check it yourself.
I am working on some C++ homework and have hit a snag, I cannot run my displayList() function in my linkedlist class. I receive the following error.
Error 1 error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'weatherstats' (or there is no acceptable conversion) c:\users\larry\documents\visual studio 2013\projects\weatherstats\weatherstats\linkedlist.h 100 1 WeatherStats
So I need to overload the << operand but I have tried using a few examples I found online but with no luck. Can someone help me with my << overload operator please?
EDIT: Added Weatherstats.cpp
EDIT 2: I created an overloaded << operand in my weatherstats.cpp file, I updated my content below. Instead of outputting my data, it outputs all data I enter as 1. I enter 2 for snow and it prints out 1 when using my displayList() function.
linkedlist.h
#pragma once
#include"WeatherStats.h"
#include<iostream>
#include<string>
using namespace std;
template <class T>
class linkedlist
{
private:
struct ListNode
{
T value; //Current value of node
struct ListNode *next; //Pointer to next node
};
ListNode *head; //Head pointer
public:
/*!
Constructors
!*/
linkedlist()
{
head = NULL;
};
/*!
Destructors
!*/
~linkedlist();
/*!
Prototypes
!*/
void appendNode(T); //Append a node to list
void insertNode(T); //Insert a node to list
void deleteNode(T); //delete a node in list
void searchList(T); //Search a node in list
void displayList() const; //Display the full list
friend ostream &operator << (ostream&, linkedlist<T> &);
};
//**
//Append Node
//**
template <class T>
void linkedlist<T>::appendNode(T newValue)
{
ListNode *newNode; //Point to new node
ListNode *nodePtr; //Move through list
//Assign newValue to new node
newNode = new ListNode;
newNode->value = newValue;
newNode->next = NULL;
if (!head)
{ //If empty assign new node as head
head = newNode;
}
else
{ //Assign head to nodePtr
nodePtr = head;
//Find last node in list
while (nodePtr->next)
{
nodePtr = nodePtr->next;
}
//Insert newNode as the last node
nodePtr->next = newNode;
}
}
//**
//Display List
//**
template <class T>
void linkedlist<T>::displayList()const
{
ListNode *nodePtr;
//Assign head to nodePtr
nodePtr = head;
//While nodePtr pointing to a node, print to screen
while (nodePtr)
{
//Print value
cout << nodePtr->value << endl; //ERROR C2679 HERE
//Move nodePtr to next node
nodePtr = nodePtr->next;
}
}
//**
//Insert Node
//**
template <class T>
void linkedlist<T>::insertNode(T newValue)
{
ListNode *newNode;
ListNode *nodePtr;
ListNode *previousNode = NULL;
//New node
newNode = new ListNode;
newNode->value = newValue;
//If list is empty assign newValue to head
if (!head)
{
head = newNode;
newNode->next = NULL;
}
else
{
//Assign head to nodePtr
nodePtr = head;
//Pass over all nodes who are less than newValue
while (nodePtr != NULL && nodePtr->value < newValue)
{
previousNode = nodePtr;
nodePtr = nodePtr->next;
}
//If new node will be first, insert before all other nodes
if (previousNode == NULL)
{
head = newNode;
newNode->next = nodePtr;
}
else
{
previousNode->next = newNode;
newNode->next = nodePtr;
}
}
}
//**
//Delete Node
//**
template <class T>
void linkedlist<T>::deleteNode(T searchValue)
{
ListNode *nodePtr; //Traverse our list
ListNode *previousNode = NULL; //Points to previous node
//Check if list is empty
if (!head)
{
cout << "This list is empty." << endl;
return;
}
//Delete head if == searchValue
if (head->value == searchValue)
{
nodePtr = head->next;
cout << head->value << " deleted" << endl;
delete head;
head = nodePtr;
}
else
{
//Set nodePtr to head
nodePtr = head;
//Skip nodes not equal num
while (nodePtr != NULL && nodePtr->value != searchValue)
{
previousNode = nodePtr;
nodePtr = nodePtr->next;
}
//Link previous node to the node after nodePtr and then delete
if (nodePtr)
{
previousNode->next = nodePtr->next;
cout << nodePtr->value << " deleted" << endl;
delete nodePtr;
}
}
}
//**
//Search List
//**
template <class T>
void linkedlist<T>::searchList(T searchValue)
{
ListNode *nodePtr; //Traverse our list
ListNode *previousNode = NULL; //Points to previous node
int counter = 0;
//Check if list is empty
if (!head)
{
cout << "This list is empty." << endl;
return;
}
//Check if head == searchValue
if (head->value == searchValue)
{
cout << head->value << " found at position 0" << endl;
}
else
{
//set nodePtr to head
nodePtr = head;
//Pass over all nodes that do not equal searchValue
while (nodePtr != NULL && nodePtr->value != searchValue)
{
previousNode = nodePtr;
nodePtr = nodePtr->next;
counter++;
}
//When nodePtr == searchValue
if (nodePtr)
{
cout << nodePtr->value << " found at position " << counter << endl;
}
else
{
cout << "-1: Value not found." << endl;
}
}
}
//**
//Destructor
//**
template <class T>
linkedlist<T>::~linkedlist()
{
ListNode *nodePtr; // To traverse the list
ListNode *nextNode; // To point to the next node
// Position nodePtr at the head of the list.
nodePtr = head;
// While nodePtr is not at the end of the list...
while (nodePtr != NULL)
{
// Save a pointer to the next node.
nextNode = nodePtr->next;
// Delete the current node.
delete nodePtr;
// Position nodePtr at the next node.
nodePtr = nextNode;
}
}
template <class T>
ostream &operator << (ostream stream, linkedlist<T> &obj)
{
stream >> obj.value;
return stream;
}
main.cpp
#include "linkedlist.h"
#include "WeatherStats.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
int int_numMonths; //Hold number of months value
double dbl_rain; //Hold rain value
double dbl_snow; //Hold snow value
double dbl_sunnyDays; //Hold sunny days value
//Create lnk_list object with weatherstats
linkedlist<weatherstats>weather_list;
cout << "Weather Data" << endl;
cout << endl;
cout << "What is the number of months you want to enter data for?: ";
cin >> int_numMonths;
cout << endl;
//Loop to enter each months values
for (int i = 0; i < int_numMonths; i++)
{
cout << "Month " << i + 1 << endl;
cout << "Enter amount of rain: " << endl;
cin >> dbl_rain;
cout << "Enter amount of snow: " << endl;
cin >> dbl_snow;
cout << "Enter number of Sunny Days: " << endl;
cin >> dbl_sunnyDays;
//Create weatherstats obj and pass it rain,snow and sunnyDays
weatherstats month_data(dbl_rain,dbl_snow,dbl_sunnyDays);
weather_list.appendNode(month_data);
}
weather_list.displayList();
}
Weatherstats.cpp
#include "WeatherStats.h"
#include <iostream>
using namespace std;
/*!
Constructors
!*/
weatherstats::weatherstats()
{
dbl_rain = 0;
dbl_snow = 0;
dbl_sunnyDays = 0;
}
weatherstats::weatherstats(double r, double s, double d)
{
dbl_rain = r;
dbl_snow = s;
dbl_sunnyDays = d;
}
/*!
Accessors
!*/
double weatherstats::getRain()
{
return dbl_rain;
}
double weatherstats::getSnow()
{
return dbl_snow;
}
double weatherstats::getsunnyDays()
{
return dbl_sunnyDays;
}
/*!
Mutators
!*/
void weatherstats::setRain(double r)
{
dbl_rain = r;
}
void weatherstats::setSnow(double s)
{
dbl_snow = s;
}
void weatherstats::setsunnyDays(double d)
{
dbl_sunnyDays = d;
}
//Overload Opperator
ostream& operator << (ostream &stream, weatherstats &obj)
{
stream <<&weatherstats::getRain << " - " << &weatherstats::dbl_snow << " - " << &weatherstats::getsunnyDays << endl;
return stream;
}
I'm going to take a stab in the dark with this, as I haven't touched templates or overloading for a couple of years.
Do you have the << operator overloaded for your weatherstats class?
Your error line is trying to print the value member variable. In your ListNode definition you say value is of type T (i.e. a template).
In your main() you are creating a linkedlist with your template type as weatherstats.
Your error also states that it cannot convert the weatherstats type.
So the question is: Are you Overloading << for the weatherstats class ?
Unfortunately, you haven't posted the code for this class, so we can't go any further than this. Edit: Code has been posted - still no evidence of overloading
(Also I think Baget makes a good point about the direction of your stream operator later on)
EDIT2: How should you call a function? Is it &classname::function or object.function()?
isn't stream >> obj.value; need to be stream<<obj.value;
it is OUTPUT stream not INPUT
#include<iostream>
using namespace std;
class TCSGraph{
public:
void addVertex(int vertex);
void display();
TCSGraph(){
head = NULL;
}
~TCSGraph();
private:
struct ListNode
{
string name;
struct ListNode *next;
};
ListNode *head;
}
void TCSGraph::addVertex(int vertex){
ListNode *newNode;
ListNode *nodePtr;
string vName;
for(int i = 0; i < vertex ; i++ ){
cout << "what is the name of the vertex"<< endl;
cin >> vName;
newNode = new ListNode;
newNode->name = vName;
if (!head)
head = newNode;
else
nodePtr = head;
while(nodePtr->next)
nodePtr = nodePtr->next;
nodePtr->next = newNode;
}
}
void TCSGraph::display(){
ListNode *nodePtr;
nodePtr = head;
while(nodePtr){
cout << nodePtr->name<< endl;
nodePtr = nodePtr->next;
}
}
int main(){
int vertex;
cout << " how many vertex u wan to add" << endl;
cin >> vertex;
TCSGraph g;
g.addVertex(vertex);
g.display();
return 0;
}
There is a problem in you addvertex method:
You have:
if (!head)
head = newNode;
else
nodePtr = head;
while(nodePtr->next)
nodePtr = nodePtr->next;
nodePtr->next = newNode;
but it should be:
if (!head) // check if the list is empty.
head = newNode;// if yes..make the new node the first node.
else { // list exits.
nodePtr = head;
while(nodePtr->next) // keep moving till the end of the list.
nodePtr = nodePtr->next;
nodePtr->next = newNode; // add new node to the end.
}
Also you are not making the next field of the newNode NULL:
newNode = new ListNode;
newNode->name = vName;
newNode->next= NULL; // add this.
Also its a good practice to free up the dynamically allocated memory. So instead of having an empty destructor
~TCSGraph();
you can free up the list in the dtor.
EDIT: More bugs
You have a missing ; after the class declaration:
class TCSGraph{
......
}; // <--- add this ;
Also your destructor is only declared. There is no def. If you don't want to give any def, you must at least have a empty body. So replace
~TCSGraph();
with
~TCSGraph(){}
Have you taken a look at Boost Graph Library and boost::adjacency_list?