I have to develop a library function for a phonebook which uses lists.
This function has to delete the nth entry from the list.
It is a linked list,and the entries are structs which contain the strings name,srnm,nmbr,addr,the int number and the next pointer.
Every time I call the function,however,VS gives me lot of exceptions and triggered breakpoints,and says I've corrupted the heap.
I have no idea of where I could have made this mistake that corrupts the heap.Please Help.
Here's what I've done so far :
typedef struct list {
char name[20];
char srnm[20];
char nmbr[20];
char addr[20];
unsigned int number;/*Contact index*/
struct list *next;
} entry;
static unsigned int count = 0;
static entry *hol = NULL;/*pointer to the head of the list*/
int delete_contact(unsigned int n) {
int i=0,k=0;
if(n>count) return -1;
hol[n-1].next = hol[n-1].next->next;
for(i=n;i<count;i++) {
hol[i]=hol[i+1];
}
for(i=n;i<count;i++)
hol[i].number = hol[i].number-1; /*Updates the contact index*/
count--; /*Updates the global variable that gives the number of contacts */
return 0;
}
Suggested solution
hol is a pointer, so, hol[n-1] etc. might not refer to a entry struct in memory, consider when n = 0. Either way, this is not how you should access different entries in your list structure.
For a singly-linked list you have to consider 3 cases,
If n = 0 (i.e. the first entry) is being deleted
If the entry to be deleted is somewhere inside the list
If the entry is the last entry in the list.
It is my understanding that number is the index of the list entry and that you've used dynamic memory allocation for the list entries. Furthermore, since you appear to be using the C89 standard (which does not allow loop variable initialization) I have adapted the code below as best as I could to C89, but I do not use that standard myself:
int delete_contact(unsigned int n) {
int i = 0;
int k = 0;
// Check if the index refers to an element not included in the list
if (n > count) { return -1; }
entry* tmp = hol;
if (n == count - 1) {
// Iterate to the last entry
while (tmp->next) {
tmp = tmp->next;
}
free(tmp); // Free the list entry
// Decrement the global counter keeping track of the
// amount of list elements
count--;
// No need to edit the contact indexes
return;
}
entry* remaining_list = hol;
if (n == 0) {
// Free the head of the list
hol = hol->next;
remaining_list = hol;
free(tmp); // tmp points to the head of the list already
} else {
// The list entry is somewhere inside the list
int idx = 0;
// Iterate until tmp points to the n-1:th entry
while (idx < n - 1) {
tmp = tmp->next;
idx++;
}
entry *to_be_freed = tmp->next; // n:th entry
tmp->next = tmp->next->next;
remaining_list = tmp->next;
free(to_be_freed);
}
// Decrement the contact index on all the remaining entries
while (remaining_list) {
remaining_list->number--;
remaining_list = remaining_list->next;
}
// Decrement the global counter keeping track of the
// amount of list elements
count--;
return 0;
}
Tips
You'd be better served by creating a more expressive list interface, possibly one that isn't bound to the values stored inside it. That way you could create a
list_size()
function and remove the global counter.
Here is a little something to get you started:
typedef struct node {
void* value;
struct node* next;
} node;
typedef struct list {
node* head;
node* tail;
size_t len;
} list;
Reference material
Linked list basics
Linked list exercises
Related
I'm learning C++ and learning linked lists. I'm currently trying to make a radix sort for this type of lists, but my approach is not working so I was wondering if anyone could advice me on how to do it. Here's my code:
void simpleList::radixSort() {
for (int i = 0; i < numberOfDigits(); i++){
Node * tmp = firstNode;
for (int j = 0; j < counter(); j++){
int pow = 10;
for (int k = 0; k < 10; k++){
if (tmp -> data % pow == k){
insertFirst(tmp->data);
tmp = tmp -> next;
}
pow= pow * 10;
}
}
}
}
The function numberOfDigits() gets you the amount of digits on the max number of the list, and counter() the amount of elements in the list. Also insertFirst() puts the number at the beggining of the list.
A few notes to help you on your way:
Radix Sort
A radix sort is any kind of (stable n-ary bucket sort) repeated until you run out of digits in your sort keys. Make your life simple: use binary as your radix.
Keys
You are using int values in your list, but that need not be the case. In general, you need a value→key function that returns an integer key for each element of your list, where “equivalent” elements return the same key. For a list of integers the value→key function is the identity function, so easy enough.
For convenience, I will use lambdas for the value→key functions below.
Reducing Passes
You can reduce the number of times you bucket sort to only those bits that are not the same for all keys. Before the first pass through your list, you do not know anything about the keys, so we can gather information at the same time as the first bucket sort:
key_type key_mask = 0; // bits to sort
key_type common_mask = ~0; // (bits set in all keys)
auto value_to_bucket_fn = [&]( const T & element )
{
// here we gather information about the keys
key_type key = user_supplied_value_to_key_fn( element );
key_mask |= key;
common_mask &= key;
// here we return our first bucket key == bit 0
return key & 1;
};
binary_bucket_sort( value_to_bucket_fn );
Once we have made that first pass, we can get a bitmask indicating which bits need sorting in our keys:
key_mask ^= common_mask; // key_mask ← set bits == bits to sort
All remaining passes can now be managed with a simple loop, ending when we run out of bits needing sorting:
for (int shift = 1; key_mask >>= 1; shift++)
if (key_mask & 1)
binary_bucket_sort( [&]( const T & element )
{
return (user_supplied_value_to_key_fn( element ) >> shift) & 1;
} );
Bucket Sort
A linked list is perfect for bucket sorts of large, unwieldly objects. Remember: the bucket sort must be stable, meaning it must not mix up the order of “equivalent” elements. This is imperative for a radix sort to work properly.
For a binary bucket sort over a linked list, life is pretty simple — only two buckets are necessary, and you only need keep track of the last node in each bucket to append.
If you are using a doubly-linked list that bookkeeping is done for you. If you are using a singly-linked list you will have to do it manually.
Node heads[2] = { Node{}, Node{} };
Node * tails[2] = { &heads[0], &heads[1] };
while (head)
{
int bucket = value_to_bucket_fn( head->data );
tails[bucket]->next = head; // append current head to correct bucket
tails[bucket] = head; // bucket’s new tail is the current head
head = head->next; // pop current head; get new current head
}
Hopefully you can see how easy this would be to expand to any number of buckets. Still, we will stick with two.
Once you have split all the nodes into the two buckets, just join them back together into your new complete list. Don’t forget to clean up the tail’s next pointer!
head = heads[0]->next;
tails[0]->next = heads[1]->next;
tails[1]->next = nullptr;
Be sure to check out trincot’s answer to see how he defined his singly-linked list with a lastNode pointer and useful functions to make all this splitting into buckets (“partitions”) and joining the final list into invocations of very inexpensive member functions.
Generics
This answer spends some time going on about keys and non-integer values. I have defined my list type’s nodes as:
struct node_type
{
T data;
node_type * next;
};
And I have defined the sorting functions as:
template <typename ValueToBucket>
void binary_bucket_sort( ValueToBucket value_to_bucket );
template <typename ValueToKey>
void radix_sort( ValueToKey value_to_key );
Then, when I sorted my test lists, I used variations of:
list <int> xs;
...
xs.radix_sort( []( int x ) { return x; } );
You can do things like observe the stability in the sort by playing with the value→key function (lambda). For example, I could define a list of integers where the one’s digit didn’t matter:
xs.radix_sort( []( int x ) { return x / 10; } );
Or a list of floats where the fractional part only mattered to two decimal places:
xs.radix_sort( []( double x ) { return static_cast <long long> ( x * 100 ); } );
I could have a list of Student where I am only interested in sorting by the student’s ID:
xs.radix_sort( []( const Student & student ) { return student.ID; } );
As long as the value→key function returns a sufficiently unique integer value we can use radix sort.
The main problem in your approach is that the only thing that can happen with a node is that it eventually gets moved to the start of the list. But there is nothing else that can happen with a node. For instance, there is no logic that leaves a node where it is and then moves on to the next. Instead the code keeps looking at the same node until it can be moved. It should be clear that this cannot result in a sorted order.
Secondly, if you are using radix 10, you will need 10 different possible destinations for a node ("buckets"), depending on the digit that is inspected. These would be linked lists as well, but you need to somehow manage them. Then when all nodes have been distributed over this buckets, the buckets should be joined again into a single list.
I would suggest using radix 2. Then you only need two "buckets". Also, I would suggest to keep track of the last node in a list (if you haven't already done so), with a lastNode member in your class.
Here is an implementation with radix 2 and the use of two bucket linked lists in each pass:
#include <iostream>
#include <vector>
class Node {
public:
Node *next = nullptr;
int data;
Node (int data): data(data) {};
Node (int data, Node *next): data(data), next(next) {};
};
class simpleList {
public:
Node *firstNode = nullptr;
Node *lastNode = nullptr;
simpleList() {}
simpleList(std::vector<int> data) {
for (auto value: data) {
append(value);
}
}
void clear() { // Does not free nodes
firstNode = lastNode = nullptr;
}
// Three variants of append. To append:
// * A node
// * A value, for which a Node will be created
// * Another linked list, which will be emptied
void append(Node *node) {
if (!firstNode) {
firstNode = node;
} else {
lastNode->next = node;
}
lastNode = node;
node->next = nullptr;
}
void append(int data) {
append(new Node(data));
}
void append(simpleList *other) {
if (firstNode) {
lastNode->next = other->firstNode;
} else {
firstNode = other->firstNode;
}
if (other->firstNode) {
lastNode = other->lastNode;
other->clear();
}
}
Node *popFirstNode() {
auto node = firstNode;
if (firstNode) {
firstNode = firstNode->next;
if (!firstNode) {
lastNode = nullptr;
}
node->next = nullptr;
}
return node;
}
void print() {
auto node = firstNode;
while (node) {
std::cout << node->data << " ";
node = node->next;
}
std::cout << "\n";
}
void radixSort() {
bool hasMoreBits = true;
simpleList *partitions[] = {new simpleList(), new simpleList()};
for (int bit = 0; hasMoreBits; bit++) {
hasMoreBits = false;
while (firstNode) {
hasMoreBits |= ((firstNode->data >> bit) >> 1) != 0;
int digit = (firstNode->data >> bit) & 1;
partitions[digit]->append(popFirstNode());
}
append(partitions[0]);
append(partitions[1]);
}
}
};
// Demo
int main() {
auto list = new simpleList({4, 9, 1, 2, 6, 8, 3, 7, 5});
list->print();
list->radixSort();
list->print();
}
Example of a base 256 (8 bit) radix sort for linked list using 64 bit unsigned integers for data. The list structure used in the code uses a pointer to pointer for the tail to simplify the code. A base 256 (8 bit, 8 sort passes) is about 8 times as fast as a base 2 (single bit, 64 sort passes) radix sort.
typedef struct NODE_{ // node struct
struct NODE_ * next;
uint64_t data;
}NODE;
typedef struct LIST_{ // list struct
NODE * phead;
NODE ** pptail;
}LIST;
NODE * RadixSort(NODE * plist)
{
LIST alist[256]; // array of lists
NODE *pnode = plist;
uint32_t i, j, k;
size_t x;
for(k = 0; k < 64; k += 8){ // radix sort
for (i = 0; i < 256; i++) { // reset alist
alist[i].phead = 0;
alist[i].pptail = &alist[i].phead;
}
pnode = plist; // split into lists
while(pnode){
x = ((pnode->data) >> k) & 0xff;
*(alist[x].pptail) = pnode;
alist[x].pptail = &(pnode->next);
pnode = pnode->next;
}
// // concatenate lists
for(i = 0; alist[i].phead == 0; i++);
plist = alist[i].phead;
j = i;
for(++i; i < 256; ++i){
if(alist[i].phead == 0)
continue;
*(alist[j].pptail) = alist[i].phead;
j = i;
}
*(alist[j].pptail) = 0;
}
return plist;
};
Here is how I defined and initialized a linked list
struct listrec
{
struct listrec *prev;
float value;
struct listrec *next;
};
listrec *head, *tail;
int main() {
int number;
cin >> number;
float content = 2.0;
for (float i = 0; i < number; i++)
{
if (i == 0)
{
head = new listrec;
head->prev = nullptr;
head->value = 1.0;
head->next = nullptr;
tail = head;
}
else
{
auto *newNode = new listrec;
newNode->value = content++;
newNode->next = nullptr;
newNode->prev = tail;
tail->next = newNode;
tail = tail->next;
}
}
return 0;
}
This is how the linked list looks like
I need to " write a function that takes two input parameters - the pointer head OR tail plus a parameter of which direction to traverse - to traverse the linked list and return the number of elements in the list. "
I have no idea how to write a function like that…
I know, if I want to count the number of elements from the first node, then I can write a function like this:
float listSize(listrec* head)
{
int count = 0;
listrec* current = head; // Initialize current
while (current != NULL)
{
count++;
current = current->next;
}
return count;
}
Or, if I want to count the elements from the last element, then
float listSize2(listrec* tail)
{
int count = 1;
listrec* current = tail;
while (tail->prev != NULL)
{
count++;
tail = tail->prev;
}
return count;
}
But how can I combine these two? Any hints would be appreciated!
Here is the function, assuming a doubly linked list:
enum class Direction {FORWARD, REVERSE};
struct Node
{
Node * previous;
Node * next;
};
unsigned int Count(Node * p_begin, Direction traverse_dir)
{
unsigned int node_count = 0U;
while (p_begin != nullptr)
{
++node_count;
if (traverse_dir == FORWARD)
{
p_begin = p_begin->next;
}
else
{
p_begin = p_begin->previous;
}
}
return node_count;
}
Per the requirement, the function takes 2 parameters, a pointer to a head or tail node, and a direction and returns the quantity of nodes traversed.
The function starts at the pointer passed, then goes forward or reverse (depending on the direction parameter), and increments the node counter. The loop stops when a null pointer is encountered, which usually signals the beginning or end of a list.
Since only a node class is used, you can inherit from the Node to make various list types:
struct Integer_Node : public Node
{
int data;
};
The data field does not play a role in traversing the list, so it was removed from the fundamental node object.
You don't need to "combine" them. You need to call one or the other depending on the direction:
enum class Direction { Forward, Backwards };
int listSize(listrec* p, Direction dir)
{
if (dir == Direction::Forward)
return listSize(p);
else
return listSize2(p);
}
This is not a review site, that being said I cannot in good conscience leave this answer without some advice for your code:
in C++ you should use RAII. A consequence of that is that you should never use explicit calls to new / delete and you should not use owning raw pointers.
count is an integer, so returning float in your functions makes no sense. Floating point data has its problems, don't use it for integers.
better name your functions. listSize and listSize2 are terrible names. Your functions don't list, they just return the size. So a better name is getSize. Also differentiating between then by a number is another terrible idea. You can use getSize and getSizeReverse.
there is no need to pass pointers to your function. Passing by reference, or even by value in your case is preferred.
you need better OOP abstractions. listrec is a list record (aka a list node). On top of this you need a class that abstracts a list. This would contain a pointer to the head of the list and a pointer to the tail of the list.
you should create a function for insertion into the list (and one for each operation on the list) and not do it manually in main.
The following code will not print the last line which displays the maximum element in the linked list below.
In the following code, I sum the linked list, print the entire linked list, print the length of the linked list, and would like to print the maximum value found in the linked list.
For some reason, the compiler does not print the last line.
#include <iostream>
#include <stdio.h>
using namespace std;
struct Node{ //if you want to convert to class, you need to assign access specifiers to public since they're private on default
int data;
struct Node *next;
}*first = NULL;
void create(int A[], int n)
{
struct Node *t; //create a temporary pointer t
struct Node *last; //pointer, points to the last node - helps me add a new node at the END of a linked list
//as of now, the linked list is empty, so we must create the first node!
first = new Node;//create new node on the heap, and first will be pointing on that new node
first -> data = A[0]; // Assign first the first element on the array
first -> next = NULL;//Should point to a null value as it is the only element on the list to start/currently
last = first; //last points on first node
for (int i = 1; i <n; i++)// i starts at element 1 since first has been assigned the 1st element in the array
{
t = new Node; //create a new node
t->data = A[i]; //fill up the data of t from A[i] which will be iterated through and assigned to data
t->next = NULL; // the next node should be pointing to NULL, as there is nothing at the moment when the iteration begins that it is initially pointing to
last -> next = t;
last = t;
}
}
int length (struct Node *p)
{
int l = 0;
while (p)
{
l++;
p = p->next;
}
return l;
}
int sum (struct Node *p){
int s= 0;
while(p){
s+=p->data;
p = p->next;
}
return s;
}
int max (struct Node *p){
int max = -32767;
while(p){
if(p->data > max){
max = p->data;
p = p->next;
}
}
return max;
}
void display (struct Node *p)
{
while (p != 0 )
{
cout<<p->data<<" ";
cout<<p->next<<" ";
p = p->next;
}
}
int main() {
int A [] = {1,2,3,18,5, 6, 7};
create (A,7);
display(first);
cout<<endl;
cout<<"The length of the linked list (the number of nodes) is: "<< length(first)<<endl;
cout<<"The sum of the linked list values (nodes) is: "<< sum(first)<<endl;
cout<<"The maximum value in the linked list (of the nodes) is: "<< max(first)<<endl;
return 0;
}
What am I doing wrong?
You have a little problem in your max function,your function never goes through the entire list since you put the p = p->next inside of the if block, you must edit it as below
int max (struct Node *p){
int max = -32767;
while(p !=nullptr ){
if(p->data > max){
max = p->data;
}
p = p->next;
}
return max;
}
It's because of that you put the p = p->next inside of the maximum checking scope and because of that if max set to 18, you couldn't point to the next of the list, since you don't have any data in the list that is bigger than 18,so list never finished and your iterator will be stopped in a fixed point and while loop will run forever!!
Your max() function is not incrementing the node pointer on every iteration, like your other functions do. If it encounters a data value that is not greater than the current max then it gets stuck in an endless loop.
You need to move the iteration out of the inner if block:
int max (struct Node *p){
int m = -1;
while (p){
if (p->data > max){
max = p->data;
}
p = p->next;
}
return m;
}
I'm trying to add elements to a list, but can't figure out why the push_back method is repeating the last added element. To illustrate:
Each node object consists of a data and head field. In the code below, I iterate through an array of ints, create a new node to store each int, and push_back the element to the list L. The repeated node is always the last one added to the list (in the picture above when iteratror i=1)
void addElements(std::list<node>& L, int arr[],std::list<node>::iterator Itor,int size){ //array decays to pointer
for (int i=1;i<size;i++){
node* n = new node;
n->data = arr[i];
n->head = Itor->head; //head of the first element in the list
L.push_back(*n);
}
}
I included the complete code of the disjoint data structure below. I read on cplusplus.com that push_back increases the container size by 1. So I'm a little perplexed why an extra node is being added to the list.
#include <iostream>
#include <list>
struct node{
int data;
node* head;
};
void makeSet(std::list<node>& L,int arr[]){ //asterick is before the variable name
node *headNode = new node;
headNode->data = arr[0]; //representative node
headNode->head = headNode; //point to itself
L.push_back(*headNode);
}
void addElements(std::list<node>& L, int arr[],std::list<node>::iterator Itor,int size){ //array decays to pointer
for (int i=1;i<size;i++){
node* n = new node;
n->data = arr[i];
n->head = Itor->head; //head of the first element in the list
L.push_back(*n);
}
}
int findSet(node* element){
return element->head->data;
}
int main(int argc, const char * argv[]) {
std::list<node>List;
std::list<node>::iterator Itor;
int dataArr[]={1,2,3,4,5};
int size = sizeof(dataArr)/sizeof(dataArr[0]);
Itor = List.begin();
makeSet(List,dataArr);
addElements(List,dataArr,Itor,size);
for (Itor = List.begin();Itor!=List.end();Itor++){
std::cout << Itor->data << std::endl;
}
}
Note that the size of the list in your example is 2. This means only nodes 0 and 1 are valid. This extra duplicate link is likely a Sentinel Value.
Often you'll find linked lists terminate with a null pointer, but it's just as easy to define the end of the list as a link that points to itself. This may have additional advantages, such as providing a one-past-the-end link to return as list::end.
Whatever its benefits, it is outside the bounds of the list so best that you not mess with it.
I have a template class OList that is an ordered linked list (elements are ordered in ascending order). It has a function called void insert(const T & val) that inserts an element into the correct place in the list. For example, If I had an OList of ints with the values { 1,3,5 } and called insert(4), the 4 would be inserted between the 3 and the 5, making OList { 1,3,4,5 }.
Now, what I have works fine when inserting elements into EMPTY OLists. However, when I use the following code:
OList<char> list;
for (int i = 0; i < 3; i++) {
list.insert('C');
list.insert('A');
}
printInfo(list);
printList(list) should output:
List = { A,A,A,C,C,C } Size = 6 Range = A...C
Instead, it outputs:
List = { A,C,C,C,
followed by a runtime error.
I have been messing with this for about 5 hours now, but I don't seem to be making any progress (aside from getting DIFFERENT wrong outputs and errors).
There are three relevant pieces of code: OList's default constructor, operator<<, printInfo(), insert(), and a helper function for insert that finds the node to insert the element. I don't see any reason to provide operator<< nor printInfo() since these seem to work fine elsewhere.
// default constructor
OList() {
size = 0;
headNode = new Node<T>;
lastNode = new Node<T>;
headNode->next = lastNode;
lastNode->next = NULL;
}
void insert(const T & val) {
if ( isEmpty() ) {
lastNode->data = val;
}
else {
Node<T> * pre = headNode;
Node<T> * insertPoint = findInsertPoint(pre, val);
Node<T> * insertNode = new Node<T>;
insertNode->data = val;
insertNode->next = insertPoint;
pre->next = insertNode;
// why is pre equal to headNode?
// I thought I changed that when using it
// with findInsertPoint()
cout << (pre == headNode) << endl;
}
size++;
}
// returns the node AFTER the insertion point
// pre is the node BEFORE the insertion point
Node<T> * findInsertPoint(Node<T> * pre, const T & val) {
Node<T> * current = pre->next;
for (int i = 0; (i < getSize()) && (val > current->data); i++) {
pre = current;
current = current->next;
}
return current;
}
lastNode is simply the last node in the list.
headNode is a "dummy node" that contains no data and is only used as a starting place for the list.
Thanks in advanced. I'm really embarrassed to be asking for homework help on the internet, especially since I'm sure the main problem is my lack of a thorough understanding of pointers.
You are passing the pointer to pre by value into findInsertPoint, so it is copied, and the function changes the copy of pointer, and when the function returns, it is still the old pre, not the pre from inside the function.
If you want to change the pointer, you must pass pointer to the pointer to the function (or reference to pointer).