Understanding Linked List in C++ - c++

I am trying to understand the concept of linked lists. So far this is what I know and where I'm having problems to understand.
//create node
struct list
{
int id; //member var
list* next; //pointer to link next list item
}
//int main()
//create list head and set it to NULL
list* head = NULL;
//instantiate list node
list* newList = new list;
//insert a list
newList->id = 20;
newList->next = NULL;
This I do not really understand what's going on.
newList->next = head;
head = newList;

NOTE: The memory "locations" I will reference in this answer are there purely for example are not meant to mimic the actual location these pointers might or might not ever point to.
Draw these relationships out on paper to visualize the results. Let's break it down by lines.
list *head = NULL;
And here is our visualization:
*head (0x00)
+-----------+
| |
| NULL |
| |
+-----------+
Now, we follow these next lines:
list *newList = new list;
newList->id = 20;
newList->next = NULL;
And that visualization:
*head (0x00) *newList (0x3a)
+-----------+ +----+------+
| | | id | next |
| NULL | +----+------+
| | | 20 | NULL |
+-----------+ +----+------+
And finally we end with your last bit:
newList->next = head;
And that alters the visualization thusly (reordered for clarity):
*newList (0x3a) +->*head (0x00)
+----+------+ | +-----------+
| id | next | | | |
+----+------+ | | NULL |
| 20 | head------+ | |
+----+------+ +-----------+
This has created the "link" that gives a LinkedList it's name. You link nodes together by some form of a reference. So what you've done is created a "head" or beginning of the list, and then you've created a secondary node in the list and placed it (logically) before head. Normally you'd then reassign your reference to newList to head since it's the new beginning of the list.
The next step would likely be (and I'm sure this what you meant with the erroneous bit that I ask about at the end of this question):
head = newList;
Which now changes the visualization to this:
*head (0x3a) +---> (0x00)
+----+------+ | +-----------+
| id | next | | | |
+----+------+ | | NULL |
| 20 | 0x00----+ | |
+----+------+ +-----------+
Also, what about the following line?
head = n; // What is 'n'? Where did you get it from? It doesn't appear anywhere else in your sample
EDIT
I altered the visualization to more accurately reflect what would be realistic. I wasn't paying attention to what I was doing when I posted the original answer so many thanks to José and his comment for bringing it to my attention the visualization was inaccurate.
In addition to altering the visuals I added a bit more information and wanted to take it a step further in saying that here's how you would use this linked list to loop over it's records.
list *node = head;
while (node != NULL) {
std::cout << "The id is " << node->id << std::endl;
node = node->next;
}

newList->next = head;
head = newList;
You start out with head set to NULL.
Then, you create a new node and let its next point to head, which is NULL.
Then, you set head to be the new node. Now, head points to a list that has one item in it.

Related

Replacing regex pattern with another string works, but replacing with NONE replaces all values

I am trying to replace all strings in a column that start with 'DEL_' with a NULL value.
I have tried this:
customer_details = customer_details.withColumn("phone_number", F.regexp_replace("phone_number", "DEL_.*", ""))
Which works as expected and the new column now looks like this:
+--------------+
| phone_number|
+--------------+
|00971585059437|
|00971559274811|
|00971559274811|
| |
|00918472847271|
| |
+--------------+
However, if I change the code to:
customer_details = customer_details.withColumn("phone_number", F.regexp_replace("phone_number", "DEL_.*", None))
This now replaces all values in the column:
+------------+
|phone_number|
+------------+
| null|
| null|
| null|
| null|
| null|
| null|
+------------+
Try this-
scala
df.withColumn("phone_number", when(col("phone_number").rlike("^DEL_.*"), null)
.otherwise(col("phone_number"))
)
python
df.withColumn("phone_number", when(col("phone_number").rlike("^DEL_.*"), None)
.otherwise(col("phone_number"))
)
Update
Query-
Can you explain why my original solution doesn't work? customer_details.withColumn("phone_number", F.regexp_replace("phone_number", "DEL_.*", None))
Ans- All the ternary expressions(functions taking 3 arguments) are all null-safe. That means if spark finds any of the arguments null, it will indeed return null without any actual processing (eg. pattern matching for regexp_replace).
you may wanted to look at this piece of spark repo
override def eval(input: InternalRow): Any = {
val exprs = children
val value1 = exprs(0).eval(input)
if (value1 != null) {
val value2 = exprs(1).eval(input)
if (value2 != null) {
val value3 = exprs(2).eval(input)
if (value3 != null) {
return nullSafeEval(value1, value2, value3)
}
}
}
null
}

Linked list - Insert at end using a rear pointer

I'm learning about linked list insertions and encountered the following code to insert a node at the end of a linked list (in a rather old and obsolete book for C++ still used I don't know why):
void Insert_End(Node * np){
if (start == NULL){
start = rear = np;
}
else{
rear -> next = np;
rear = np;
}
}
My question is shouldn't it be
np -> next = rear;
PS : np is the new node being inserted at the end, rear points to the last node, start points to the first node.
My question is shouldn't it be np -> next = rear;
No,following pictures may help you understand easily.
When you do start = rear = np; for the first time all the 3 nodes may look like below.
------
| np |
------
^ ^
| |
---- ----
|start| | rear|
---- ----
for the successive insertion:
when you do rear -> next = np; your list may look like below.
note: rear is still pointing to previous last node of the list and np1 is pointing to np2.
------ -----
| np1 | ---> | np2 |
------ -----
^ ^
| |
---- ----
|start| | rear|
---- ----
when you do rear = np; your rear gets updated to point current last node.
------ -----
| np1 | ---> | np2 |
------ -----
^ ^
| |
---- ----
|start| | rear|
---- ----
My question is shouldn't it be np -> next = rear;
No, because then no node would be pointing to np, and therefore it wouldn't be part of any list (other than the list whose head is np). Furthermore, np wouldn't be at the rear, since its next would be pointing at a node (the node that was rear previously). The example is a correct implementation.

MySQL c++ connector: what is the correct way to use SetBlob() to set multiple blob data in a query?

I asked the same question on stackexchange db admin, that seems to be the proper place for the question, but the problem is no one even view the question. So I post the same question here again:
I am working on Mysql table insertion. The table creation statement is like:
CREATE TABLE files_table (fid INT NOT NULL AUTO_INCREMENT, idx TINYBLOB, head TINYBLOB, size BLOB, PRIMARY KEY(fid));
I could insert record manually
mysql> select * from files_table order by fid asc;
+-----+------+------+------------+
| fid | idx | head | size |
+-----+------+------+------------+
| 1 | 1 | 1 | 1 |
+-----+------+------+------------+
But when I use the connector to add the next value by using c++ connector:
class StreamBufferData : public std::streambuf
{
public:
StreamBufferData(const char *in_data, size_t in_size)
{
setg(in_data, in_data, in_data + in_size);
}
};
enum{QUERY_SIZE=256;}
char ins[QUERY_SIZE];
strcpy(ins, "INSERT INTO files_table (idx, head, size) VALUES (?,?,?)");
try
{
std::unique_ptr<sql::PreparedStatement> statement(ptr_connection->prepareStatement(ins));
char test_data[2] = "0";
StreamBufferData buffer0(test_data, 2);
std::istream test_s0(&buffer0);
statement->setBlob(1, &test_s0);
strcpy(test_data, "1");
StreamBufferData buffer1(test_data, 2);
std::istream test_s1(&buffer1);
statement->setBlob(2, &test_s1);
strcpy(test_data, "2");
StreamBufferData buffer2(test_data, 2);
std::istream test_s2(&buffer2);
statement->setBlob(3, &test_s2);
statement->executeUpdate();
}
catch(sql::SQLException &e)
{
std::cout << e.what() << ‘\n’;
return;
}
The result is :
+-----+------+------+------------+
| fid | idx | head | size |
+-----+------+------+------------+
| 1 | 1 | 1 | 1 |
| 2 | 2 | 2 | 2 |
+-----+------+------+------------+
Only the last value is correctly inserted into the table. My question is: what is the proper way to user msql::PreparedStatement::setBlob() to set multiple blobs in a query?
[environment]
Ubuntu 16.04.2
MySQL 5.7
MySQL connector version: 7.1.1.7
boost 1.58.0
g++ 5.4.0
Thanks for your help
Rong
The different std::istream objects point to the same buffer which allocated by test_data. I thought the istream object will copy the value in the char array. The fact is, it is not.
It also worths to point out that if the std::istream object is destroyed before the statement->executeUpdate() executed. The last stream object will be filled into the first column of the table, which might be an undefined behavior on my machine (Ubuntu 16.04.2 LTS). It looks like:
+-----+------+------+------------+
| fid | idx | head | size |
+-----+------+------+------------+
| 1 | 1 | 1 | 1 |
| 2 | 2 | | |
+-----+------+------+------------+
So, if the table has strange results like the previous table, check the code to make sure the std::stream, the StreamBufferData and the pointer pointing to the buffer are still valid until statement->executeUpdate() executed.

C++ list program freeze when i call a function

This code must insert character 'p' before character 'q' how many times 'q' appear in list.
When I call function insert_before (insert_before('q','p') ) my program freezes. I don't write all the code here. The rest of the program works fine.
struct node
{
char character;
node* next;
};
node *fisrt , *end;
void insert_before(char val_search,char val_inserted)
{
node *c,*a;
c=first;
do {
if (c->next->character==val_search)
{
a= new node ;
a->character=val_inserted ;
a->next=c->next;
c->next=a;
c=c->next;
}
else
c=c->next;
} while (c) ;
}
When you find the value p, you insert a new entry before the found entry.
This means, next time you will find the same entry again and insert another new entry before the found entry
+---+ +---+
| x |->| p |
+---+ +---+
c
will become
+---+ +---+ +---+
| x |->| q |->| p |
+---+ +---+ +---+
c
and then it will become
+---+ +---+ +---+ +---+
| x |->| q |->| q |->| p |
+---+ +---+ +---+ +---+
c
and so on.
Because this will never end (until you run out of memory), the program appears to freeze.
The problems
Let's suppose that you have a list with a unique element 'q' in it: first and last would both point to that single node. And the next pointer of the node would be nullptr.
When you execute insert_before() you start with c=first. So c points to this unique node which has next being nullptr. Unfortunately this instruction: if (c->next->character==val_search) would dereference the nullptr. This is undefined behavior and might cause the symptoms that you describe.
If your searched value is not the first element, your code would work in principle. Unfortunately, after having inserted the element, you continue to loop: you'd then loop at the new element, and the condition would be true again, so that you will insert again a new element and so on, endlessly looping until your list exhausts all the memory. This also would cause freeze.
By the way, do you really want to insert 'p' before all the 'q's in the list ?
First correction
Just correct the loop, being more careful:
void insert_before(char val_search,char val_inserted)
{
node *c,*a;
for (c=first; c && c->next; c=c->next) {
if (c->next->character==val_search)
{
a= new node ;
a->character=val_inserted ;
a->next=c->next;
c->next=a;
c=a;
}
}
}
Note that this code, exactly as your code, doesn't handle properly the insertion in front of the list.
Second fix:
To be able to insert in front, you need something like this:
void insert_before(char val_search,char val_inserted)
{
node *c,*a, *prev=nullptr;
for (c=first; c ; prev=c, c=c->next) {
if (c->character==val_search)
{
a= new node ;
a->character=val_inserted ;
a->next=c;
if (prev)
prev->next=a;
else first=a;
}
}
}
Live demo
Inside if {}, change c=c->next to c=a->next.

Pointer-to-pointer access

Can somebody explain this to me:
(((((*(parent))->leaves))[7])->zone_id)
pointers to pointers are really confusing to me. This is the expression I got from the watch in debug mode. I am trying to access to the string zone_id inside the last element of tree (with 10 elements, each element for different number 0-9).
EDIT: this is the whole search function, hope it is enough to understand:
string Tree::search(string str, node** parent, int num) {
int value;
if (num < str.length()) {
value = boost::lexical_cast<int> (str.substr(num, 1));
if ((*parent)->leaves[value] != NULL && num != str.length() -1) {
search (str, &((*parent)->leaves[value]), num+1);
} else if (num == str.length() -1) {
if ( (*(parent)->leaves)[value]->zone_id.empty() )
cout<<"Yep.";
else
return (string) "No_results.";
}
}
}
and structure:
struct node {
string zone_id;
node* leaves [10];
};
Well let's get rid of some brackets to simplify it a bit:
(*parent)->leaves[7]->zone_id
Now it's much easier to understand. We are dereferencing parent (*parent) which gives us a pointer to some object that has an array member called leaves. So we access the element of that array with index 7, which gives us another pointer, this time pointing to an object that has a member called zone_id. We then access that zone_id member.
This is all assuming there's no operator overloading involved.
Diagrammatically (an arrow is "points to"):
________ _________ ___________ ___________
| parent |-->| *parent |-->| struct: | ,-->| struct: |
|________| |_________| | leaves[0] | | | zone_id |
| leaves[1] | | | ... |
| leaves[2] | |
| leaves[3] | |
| leaves[4] | |
| leaves[5] | |
| leaves[6] | |
| leaves[7] | --'
| leaves[8] |
| ... |
Removing the parenthesis makes it actually easier to read, in my mind:
(*parent)->leaves[7]->zone_id
So, we have a pointer to a pointer of leaves. (*parent) makes a dereference to that pointer (so fetches what it the pointer points at). So now we have a pointer to leaves, which is an array of 10, so we use element 7, and the pointer here is used to fetch the zone_id.
It does get a bit complicated, but this is far from the most complicated structure I have seen. If it helps you, you could break it down:
Parent *this_parent = *parent;
Leave *leaf = this_parent->leaves[7];
... use leaf->zone_id;
(
(
(
(
(
*(parent)
)
->leaves
)
)
[7]
)
->zone_id
)
dereference parent
access the leaves member
index the 7th element
access the zone_id member.