1

I'm trying to create code that will insert anywhere in a list. I will also convert this to replace the value of the node in the given position.

So far my code is:

#include<stdio.h>
#include<stdlib.h>

struct node* createNode(int,int);

struct node {
    int data, posi;
    struct node *next;
};

struct node *head = NULL;
struct node *tail = NULL;


struct node * createNode(int data, int pos) {
    struct node *ptr = (struct node *) malloc(sizeof (struct node));
    ptr->data = data;
    ptr->posi = pos;
    ptr->next = NULL;
    return ptr;
}

void insertAtPos(int pos, int data) {
    struct node *temp, *ptr = createNode(data,pos);
    int x = 0, i = 1, inserted = 0, duplicate = 0;

    if (head == NULL || pos == 1) {
            if (!head) {
                    head = ptr;
                    tail = ptr;
                    return;
            }
            ptr->next = head;
            head = ptr;
            return;
    }
    temp = head;
    while (temp) {
        x = temp->posi;
        if (pos == i + 1) {
            printf("pos %d - temp %d - data %d",pos,x,temp->data);
            if(pos == x){
                duplicate = 1;
                break;
            }else{
                ptr->next = temp->next;
                temp->next = ptr;

                if (ptr->next == NULL)
                        tail = ptr;
                inserted = 1;
                break;
            }
        }
        i++;
        temp = temp->next;
    }
    if (!inserted)
            printf("You've entered wrong position\n");

    if(duplicate == 1){
        printf("Duplicate position!\n");
    }
}

In this code I'm trying to get the current value and position of the node in the list but all i get is the previous value. That's why I had to use +1 to get the current position.

I'm also trying to make it so that no duplicate position would be inserted in the node and that the user can insert positions 1, 3 and 5 simultaneously.

Is there any way for me to get the current value and position of the node in this list? If so, how would I do it?

Current output is that I am still able to add to the same position in the list

embedded_guy
  • 1,939
  • 3
  • 24
  • 39
magicianiam
  • 1,474
  • 7
  • 33
  • 70
  • 1. What output are you *getting*? 2. What output are you *expecting*? 3. What does the definition of `struct node` look like (include the description of members). 4. If you're preference is to update existing nodes, why *create* a new node right out of the gate? Wouldn't make more sense to only do that when you know you did *not* find the node to update? – WhozCraig Sep 29 '13 at 05:46
  • @WhozCraig sorry will post the rest of the code, for 4 thats what the else is for to only add the node when it is not found, though this was from a previous code which i am currently editing to fit my new scenario. – magicianiam Sep 29 '13 at 05:51
  • OK. is this supposed to be something like a sparse-array? It appears so, just wanted to clarify. – WhozCraig Sep 29 '13 at 05:54
  • @WhozCraig would you mind defining sparse-array. thank you – magicianiam Sep 29 '13 at 05:55
  • 1
    Think of it as an array that doesn't actually contain sequential elements in the traditional sense. Its akin to a map, where the "key" is the ordinal position provided. Like any array, there can only be one "value" at any given location. There can't be two element `[1]`s for example. But you can have values at `[1]` and `[10000]` and where a regular array requires 10001 elements, a spare array as a linked list requires only two. One with `posi=1`, and another with `posi=10000` Does that about sum it up? – WhozCraig Sep 29 '13 at 05:58
  • @WhozCraig yes very much, thank you for that definitive explanation, and yes that is what im trying to achieve here. is it possible? and how would i do it with just linked list since i think it is easier done with array. – magicianiam Sep 29 '13 at 06:01
  • Of course its easier with a true array. The convenience you pay for with the space requirements. An array with a single element at "position" 1000000 requires 4-million bytes on a 32-bit `int` platform. A *sparse* array requires only one "node". But things like insertion-time, seek time, etc, are all radically changed. Of course it is possible. Is this a homework problem? or is using a real array a possibility? If its homework lets just work on fixing your code. – WhozCraig Sep 29 '13 at 06:10
  • @WhozCraig yes this is a homework problem, else i would have already used array to deal with this. but we were required to use linked list instead thus this problem. would you mind helping me out here. thank you – magicianiam Sep 29 '13 at 06:15
  • Sure I'll post something. I think I understand the problem, and if so, you're making this hard on yourself. Lemme see what I can come up with. – WhozCraig Sep 29 '13 at 06:26
  • @WhozCraig forgive me this is not my day, also im not a big fan of linked list. thank you :) – magicianiam Sep 29 '13 at 06:28
  • @WhozCraig scratch that got it for delete, though i could use some assistance in inserting without replacing the value, i know that i just need to point the new data to the current node and insert the new data. – magicianiam Sep 29 '13 at 07:14
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/38260/discussion-between-magicianiam-and-whozcraig) – magicianiam Sep 29 '13 at 07:36

2 Answers2

3

The general idea of insertion/updating into a sparse array is to only add nodes when you arrive at a node at a larger position. Of course, you need the previous node pointer to do that, so keep one hopping along for the scan while you find where to put your data.

And some notes:

  • Don't cast malloc() in C programs.
  • I left the list cleanup as a task for you.
  • This updates an existing node if the position given is already in the list. if you want to shove a node into that position and increment the elements after it until a gap is found, that is considerably more work. It is doable, however.

With that. here you go.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

struct node* createNode(int,int);

struct node {
    int data, posi;
    struct node *next;
};

struct node *head = NULL;
struct node *tail = NULL;


struct node * createNode(int data, int pos)
{
    struct node *ptr = malloc(sizeof(*ptr));
    ptr->data = data;
    ptr->posi = pos;
    ptr->next = NULL;
    return ptr;
}

void insertAtPos(int pos, int data)
{
    struct node *ptr = head, *prev = NULL;
    while (ptr && ptr->posi < pos)
    {
        prev = ptr;
        ptr = ptr->next;
    }

    // make sure we have a node.
    if (ptr)
    {
        // Case 1: update existing element.
        if (ptr->posi == pos)
        {
            // update in place
            ptr->data = data;
        }

        // Case 2: insert new element
        else if (prev)
        {
            prev->next = createNode(data, pos);
            prev->next->next = ptr;
        }

        // Case 3: new list head.
        else
        {
            head = createNode(data, pos);
            head->next = ptr;
        }
    }
    else if (prev)
    {
        // means we hit the end of the list.
        prev->next = createNode(data, pos);
    }

    else
    {   // means empty list. new head.
        head = createNode(data, pos);
    }
}

void print()
{
    struct node *p = head;
    while (p)
    {
        printf("list[%d] = %d\n", p->posi, p->data);
        p = p->next;
    }
    printf("\n");
}

int main()
{
    int i = 0;
    srand((unsigned)time(NULL));

    // fill our list with some elements
    for (i=0;i<10;++i)
        insertAtPos(rand() % 20 + 1, rand() % 100);
    print();

    // add or update element
    insertAtPos(15, 100000);
    print();

    // update element at location 20;
    insertAtPos(15, 200000);
    print();

    // prove we can add an element at beginning of list
    insertAtPos(0, 1000);
    print();

    // prove we can add an element at end of list
    insertAtPos(100, 2000);
    print();

    return 0;
}

Output (Random)

list[3] = 86
list[5] = 10
list[9] = 63
list[12] = 86
list[14] = 93
list[19] = 86
list[20] = 49

list[3] = 86
list[5] = 10
list[9] = 63
list[12] = 86
list[14] = 93
list[15] = 100000
list[19] = 86
list[20] = 49

list[3] = 86
list[5] = 10
list[9] = 63
list[12] = 86
list[14] = 93
list[15] = 200000
list[19] = 86
list[20] = 49

list[0] = 1000
list[3] = 86
list[5] = 10
list[9] = 63
list[12] = 86
list[14] = 93
list[15] = 200000
list[19] = 86
list[20] = 49

list[0] = 1000
list[3] = 86
list[5] = 10
list[9] = 63
list[12] = 86
list[14] = 93
list[15] = 200000
list[19] = 86
list[20] = 49
list[100] = 2000

EDIT Request for how shove-in insertion is done.

To slip a new item into a given index potentially requires updating existing indexes after it. The premise is that the following should build a list with ascending posi values:

int main()
{
    int i = 0;
    srand((unsigned)time(NULL));

    // fill our list with some elements
    for (i=0;i<10;++i)
        insertAtPos(0, rand() % 100);
    print();

    return 0;
}

Note the index we're inserting with. It is always zero. The prior version of insertAtPos() would simply replace the existing value repeatedly and we would end with a list of a single node (posi = 0). To slip a value and adjust the list accordingly we should instead have a perfect sequence of 0..9 values for posi. This can be done as follows:

void insertAtPos(int pos, int data)
{
    // same as before. find the right slot
    struct node *ptr = head, *prev = NULL;
    while (ptr && ptr->posi < pos)
    {
        prev = ptr;
        ptr = ptr->next;
    }

    if (prev)
    {
        // slip new node in.
        prev->next = createNode(data, pos);
        prev->next->next = ptr;
    }
    else
    {   // no prev means this goes to the head of the list.
        head = createNode(data, pos);
        head->next = ptr;
    }

    // it is possible the new node has the same
    //  index as its successor. to account for this
    //  we must walk successor nodes, incrementing
    //  their posi values until a gap is found (or
    //  end of list).
    while (ptr && (ptr->posi == pos++))
    {
        ptr->posi++;
        ptr = ptr->next;
    }
}

Run with the aforementioned main()..

list[0] = 90
list[1] = 34
list[2] = 45
list[3] = 27
list[4] = 45
list[5] = 88
list[6] = 75
list[7] = 50
list[8] = 68
list[9] = 41

And of course, your values will vary due to the nature of rand(). A slightly different main() with two loops of insertion, one that always inserts at slot-0, the other that always inserts at slot-4.

int main()
{
    int i = 0;
    srand((unsigned)time(NULL));

    // fill our list with some elements
    for (i=0;i<5;++i)
        insertAtPos(0, rand() % 100);
    print();
    for (i=0;i<5;++i)
        insertAtPos(4, rand() % 100);
    print();

    return 0;    
}

Should result in identical indexing, but obviously different values (again, it is `rand(), after all).

list[0] = 74
list[1] = 35
list[2] = 72
list[3] = 22
list[4] = 0

list[0] = 74
list[1] = 35
list[2] = 72
list[3] = 22
list[4] = 40
list[5] = 38
list[6] = 31
list[7] = 57
list[8] = 42
list[9] = 0

Note how the 0 value was shoved all the way through to the end of the list. It was in the 4-index so it was "pushed" down with each insertion, as was each number we inserted one after another.

Finally, to prove this properly only adjusts the indexing until a detected gap, consider this:

int main()
{
    int i = 0;
    srand((unsigned)time(NULL));

    // fill our list with some elements
    for (i=0;i<10;i+=2)
        insertAtPos(i, rand() % 100);
    print();
    for (i=0;i<2;++i)
        insertAtPos(3, rand() % 100);
    print();

    return 0;
}

This should insert values in indexes 0,2,4,6,8 initially, then insert two values at slot "3". The first insertion should give us indexes 0,2,3,4,6,8. The second insertion should give us indexes 0,2,3,4,5,6,8.

list[0] = 22
list[2] = 3
list[4] = 91
list[6] = 15
list[8] = 68

list[0] = 22
list[2] = 3
list[3] = 94
list[4] = 48
list[5] = 91
list[6] = 15
list[8] = 68

As expected.

Community
  • 1
  • 1
WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • 1
    Pay special attention to the third item in the punch-list. It essentially means if you already have items at position 1,2,3,6 and you "insert" an item at position 2, rather than updating the item it shoves it in between 1 and (the old) 2, then increments further-down item positions until a gap is found. The result would be a list with items in 1,2,3,4,6, with 2 being the new item, 3 being the old 2, 4 being the old 3, and 6 and 1 both being what they were before. The posted code does *not* do that, but hopefully you can see how it *could* be done. – WhozCraig Sep 29 '13 at 06:46
  • got it and its working great, thank you, yeah i got it how to work on the insert while appending a new value, though do you have any idea how to work on this for delete on specific position? thank you – magicianiam Sep 29 '13 at 06:54
  • @magicianIam its the same premise, but a little easier. You still use to pointers, prev and ptr, but you're looking for an exact match *only*. If found the node will be deleted by extracting it from the list, setting prev->next to ptr->next *before* the delete. There is one special case that happens when prev is still NULL. This can only happen when the list *head* is the one being deleted. In that case simple set head = ptr->next before deleting the ptr node. – WhozCraig Sep 29 '13 at 08:20
  • i got the delete, im working on the insert again for now, I just cant get it to append in the list. i tried this: prev->next = createNode(data, pos); ptr->next = prev->next->next; --but it just empties the nodes after the newly inserted node. any ideas? thanks – magicianiam Sep 29 '13 at 08:23
  • 1
    By insert, you mean the shove-in I was referring to before ? If so, it is a little tricky, and potentially expensive, but still doable. Is the desired result as I described it ? (see general comment below your question for the description). – WhozCraig Sep 29 '13 at 08:43
  • yes im trying to work on that shove-in function, but i just end up replacing the values of the node. here's what i got: -----prev->next = createNode(data, pos); prev->next->next = ptr->next; ptr = prev->next; --- here prev->next holds the new node, prev->next->next holds to where ptr->next is pointing and ptr = prev->next now holds the new node. i think my logic is correct. do correct me if im wrong. thank you. also yes the code works perfectly as you've described it i just need to add the shove-in part – magicianiam Sep 29 '13 at 08:46
  • Its pretty close. there are special cases to consider when `prev` is NULL. Also, assuming it isn't, the order should be `prev->next = createNode(data,pos);`, then `prev->next->next = ptr;` From there you walk forward, starting with `ptr` and increment `posi` for each successive node until a gap is found. Its easier to see in code. i'll try and work something up. – WhozCraig Sep 29 '13 at 08:51
  • yeah i havent gotten to the null part too, also the increment one. can you help me with this? thank you. – magicianiam Sep 29 '13 at 08:53
  • 1
    You'll likely be surprised that it is actually easier to do in-code than the update-in-place method. – WhozCraig Sep 29 '13 at 09:10
  • works perfectly thank you very much, i guess my code was just lacking the pos part since there were duplicate positions in the list whenever i tried to add a new node on an already existing position. once again thank you. – magicianiam Sep 29 '13 at 09:23
1

Here's my function that lets you insert anywhere in the list, given a position number. It implicitly gives each item a number based on how many items had to be traversed to get to it + 1. So the head has node number 1.

void insertAfterPos(struct node** head_ref, struct node* link, int new_data, int pos)
{

// allocate new node 
struct node* new_node = malloc(sizeof(struct node));
struct node* cur = *head_ref; //initialise current node as head
cur->next = link;
int nodenum = 1;
// put in the data
new_node->data = new_data;
while (cur !=NULL || nodenum <= pos) {
    if (nodenum == pos) {
    //Make next of new node next of current node 
    new_node->next = cur->next;

    //Make the next of current node new_node
    cur->next = new_node;
    }
    nodenum++;
    cur = cur->next; //move forward
    }
}

This function was written within the framework that the access to the list by all of the insert functions would be through a head reference, or a pointer to a pointer to the head hence the node **head_ref argument. The second argument in this function, link, should be head->next as the current node can't access the next pointer contained in the head node from the head reference. An example of it's use

insertAtPos(&head,head->next,10,2)

will insert the value 10 in the node after the second node.

Interestingly, if you enter a position greater than the size of the list, it will just put it at the end.

Tsukimaru
  • 11
  • 2