Reputation: 1722
This was an interview question and I thought I'd share it with the rest of you.
How does one efficiently add to the tail of a linked list without using an "if"?
Remove the if from this function. (?
is still an if
).
typedef struct tNode_ tNode;
struct tNode_ {
tNode* pNext;
int data;
};
tNode* pHead = NULL;
tNode* pTail = NULL;
AddTail(tNode* pNode){
if(!pTail) {
pHead = pNode;
}
else {
pTail->pNext = pNode;
}
pTail = pNode;
pTail->pNext = NULL;
}
Upvotes: 4
Views: 2467
Reputation: 98088
tNode pHead;
tNode pTail;
void init() {
pHead.pNext = &pTail;
pTail.pNext = &pHead;
}
AddTail(tNode* pNode){
pTail.pNext->pNext = pNode;
pNode->pNext = &pHead;
pTail.pNext = pNode;
}
Upvotes: 1
Reputation: 25484
I would use a dummy element (or sentinel node as they call it) for each list. Appending to the head becomes appending to the dummy, appending to the tail is just appending to the last element which then by definition exists.
typedef struct tNode_ tNode;
struct tNode_ {
tNode* pNext;
int data;
};
// The Remove operation must never remove this dummy!
tNode* pDummy = (tNode*)calloc(1, sizeof(tNode));
tNode* pHead = pDummy;
tNode* pTail = pDummy;
AddTail(tNode* pNode){
pTail->pNext = pNode;
pTail = pNode;
pTail->pNext = NULL;
}
Upvotes: 1
Reputation: 373042
One (admittedly silly) way to do this is to use the behavior of the short-circuiting logical operators &&
and ||
. For example, you could do this:
AddTail(tNode* pNode){
pTail || (pHead = pNode);
!pTail || (pTail->pNext = pNode);
pTail = pNode;
pTail->pNext = NULL;
}
This works because if ptail
is null, the first part of the first statement will evaluate to false, forcing evaluation of the second half of the ||
statement. If it's non-null, the second half of the statement will not be evaluated. Similar logic works for the next statement.
That said, this is a very silly interview question and I honestly don't know what they're getting at. Personally, I would question the wisdom of someone trying to assess your ability to write code like this.
Hope this helps!
Upvotes: 2
Reputation: 1722
typedef struct tNode_ tNode;
struct tNode_ {
tNode* pNext;
int data;
};
/* normal initialization for pHead */
tNode* pHead = NULL;
/* the trick is to point at where you want the next pointer to go
* instead of saving a pointer to the node.
*/
tNode** ppTail = &pHead;
AddTail(tNode* pNode){
pNode->pNext = NULL;
/* update the next pointer */
*ppTail = pNode;
/* save the address of the next pointer */
ppTail = &pNode->pNext;
}
main(){
int cnt;
tNode* pNew;
for(cnt=0; cnt<10; cnt++){
pNew = malloc(sizeof(tNode));
pNew->data = cnt;
AddTail(pNew);
}
for(pNew = pHead; pNew; pNew = pNew->pNext){
printf("%d\n", pNew->data);
}
}
Upvotes: 1