cs 32: discussion
TRANSCRIPT
LinkedLists
• Akeycomponentofalinkedlistisanode,whichisasingleunitofdata.
• Thefirstboxcarriesavalue,andthesecondisapointer toanothernode• HereisanexamplenodedefinitionintheformofaC++struct:Typedef int ItemType;Struct Node{
ItemType value;Node *next;
};
value *next
LinkedLists
• Linkedlistisaseriesofnodes,eachpointingtothenextone.
• Thelastnode’snextpointerisNULL.
• Whatistheinformationyouneedtocompletethepicture?
HeadPointer!
• Obviously,youneedtoknowwhereitbegins.
• Wekeepapointerthatpointstothefirstitemandcallitthehead
pointer.
• e.g.Node *head;
LinkedLists(Min.Requirements)
• Youneedadescription ofanode,whichmustcontainanextpointer.
• Youneedahead pointerthatpointstothefirstnode.
• Thelistmustbeloop-free(unlessitisacircularlylinedlist,inwhich
caseone(andonlyone)loopmustexist).
LinkedLists(Insertion)
• Whataboutinsertioninthemiddleofthelist?• Attheendofthelist?
End(q):q->next=p;p->next=NULL;Middle(afterq):p->next=q->next;q->next=p;
LinkedLists(Search)
Node* Search(int key, Node* head){ Node *q = head;while(q != NULL) {
if(q -> value != key) q = q -> next; //move to next
else return q;
} return NULL; }
LinkedLists(Removal)
• Supposethereisanitemthatyouwanttoremove,anditispointedbyapointer,sayp.
• CanIjustdo“deletep;”?
• Weneedtosetthepreviousnode’s(q)next pointertopointtothenextnodeofp !
LinkedLists(Removal)
• Whenlookingupp,keepthepointertothepreviousnode(q).
• Then…q->next = p->next;delete p;
LinkedLists(Removal)
• SanityChecks• Doesitworkifp==head?• Doesitworkifp pointstothelastone?
q->next = p->next;Delete p;
LinkedLists(Removal)
• Ifp==head,thereisno”previous”nodetop.• Makeanexceptionforthis.
• Weneedtoresettheheadpointer.
head = p->next;Delete p;
LinkedLists(Removal-- Summary)void remove(int valToRemove, Node* head) {
Node *p = head, *q = NULL; while (p != NULL) {
if (p->value == valToRemove) break;
q = p; //q keeps track the previous of p p = p->next;}
if (p == NULL) return;
if (p == head) //node to remove is head head = p->next;
elseq->next = p->next;
delete p; }
What’sniceaboutlinkedlists
• Veryefficientinsertion• Flexiblememoryallocation
• Thinkaboutwhatyoushoulddoifyouhavetogrow/shrinkadynamicallyallocatedarray.
• Andyes,thereisalittleoverhead,butthat’sthepricewepay.
• Simpletoimplement
What’snotsoniceaboutlinkedlists
• Slowsearch(i.e.accessingacertainelement,e.g.”getthe
4237th item”)
• Usually,searchistheoperationthatmattersmorethaninsertion
orremoval.
Variations
• SortedLinkedLists• Makechangestotheinsertionmethod.
• DoublyLinkedLists• Eachnodehasprev andnext pointers.• Atail pointeriskepttopointtothelastnode.• Whydoyouthinkthisisuseful?
• CircularlyLinkedLists• Thelastnode’snextpointerpointstothefirstone.• Essentially,thereisno”first”node.
AClassicProblemaboutCircularlyLinkedList
• Givenaheadnodeofalinkedlist,howtoverifywhetherthereisaloopinthelinkedlistornot?
DoublyLinkedList
• Alinkedlistwhereeachnodehastwopointers:• Next– pointingtothenextnode• Prev – pointingtothepreviousnode
struct Node { int value; Node *Next; Node *Prev;
};
DoublyLinedList
• That’showitlookslike:
• FeaturestocaptureaDLL:• Twopointers:head,tail• head->prev =NULL• tail->next=NULL• head==tail==NULLwhenlistisempty
Insertion
FourdifferentconditionstoinsertanewnodeP• 1.Insertbeforethehead;• 2.Insertafterthetail;• 3.Insertsomewhereinthemiddle;• 4.Whenlistisempty;
Insertion(Beforehead)
• 1)Settheprev ofheadtothenewnodep• head->prev =p;
• 2)Setthenext ofp tohead• p->next=head;
• 3)p becomesthenewhead• head=p;
• 4)head->prev =NULL;
Insertion(Aftertail)
• Quitethesameasinsertionbeforehead:
tail->next=p;p->prev =tail;tail=p;p->next=NULL;
Insertioninthemiddle(afternodeq)
• 1)Fixthenextnodeofq first:• Node*r=q->next;
• 2)Pointbothnext ofq andprev ofr top• q->next=r->prev =p;
• 3)Pointbothsidesofp toq andr respectively:• p->prev =q;• p->next=r;
Insertioninthemiddle(afternodeq)
• Ordoitwithoutr:
• p->prev =q;
• p->next=q->next;
• q->next=q->next->prev =p;
Insertion(toanemptylist)
• Howdowerepresentanemptylist?
• head==NULL(Ortail==NULL;Orhead==tail==NULL)
• 1)Insertion,justsetp ashead aswellastail:
• head=tail=p;
• 2)Don’tforgettosetNULLonbothsides:
• p->next=p->prev =NULL;
Search
• Justlikethesinglylinkedlist.
Node* Search(int key, Node* head){
Node *q = head;
while(q != NULL) {
if(q -> value == key) return q;
else q = q -> next; //iterate to the next node
}
return NULL;
}
Node* Search(int key, Node* tail){
Node *q = tail;
while(q != NULL) {
if(q -> value == key) return q;
else q = q -> prev; //iterate to the previous node
}
return NULL;
}
Removal
• Morecomplexthansinglylinkedlist.
• Checkifthenodep isthehead(p==head).Letthisboolean beA.
• Checkifthenodeisthetail(p==tail).Letthisboolean beB.
Removal
Fourcases:• Case1(A,butnotB):P istheheadofthelist,andthereismorethanonenode.
• Case2(B,butnotA):P isthetailofthelist,andthereismorethanonenode.
• Case3(AandB):P istheonlynode.• Case4(notAandnotB):P isinthemiddleofthelist.
RemovalCase1(P ishead)
• 1)Updatehead• head=head->next;
• 2)deletep• deletep;
• 3)Settheprev ofhead toNULL• head->prev =NULL;
RemovalCase2(P istail)
• 1)Updatetail
• tail=tail->prev;
• 2)deletep
• 3)Setthenext oftail toNULL
• tail->next=NULL;
RemovalCase4(P isinthemiddle)
• 1)Fixtheprev andnextofp:• Node*q=p->prev;• Node*r=p->next;
• 2)Concatenateq andr:• q->next=r;• r->prev =q;
• 3)Deletep
RemovalCase4(Equivalentimplementation)
• Ifwedonotfixwithq andr:• p->prev ->next=p->next;• p->next->prev =p->prev;• deletep;
RemovalSummaryvoidremoveNodeInDLL(Node*p,Node&*head,Node&*tail){if(p==head&&p==tail)//case3head=tail=NULL;
elseif(p==head){//case1head=head->next;head->prev =NULL;
}elseif(p==tail){//case2tail=tail->prev;tail->next=NULL;
}else{//case4p->prev ->next=p->next;p->next->prev =p->prev;
}deletep;
}
Copyingadoublylinkedlist
• 1)Createheadandtail forthenewlist• 2)Iteratethroughtheoldlist.Foreachnode,copyitsvaluetoanewnode.
• 3)Insertthenewnodetothetailofthenewlist.• 4)Repeat3untilwehaveiteratedtheentireoldlist.SetNULLbeforehead andnextoftail.
Cautionsaboutcodingwithalinkedlist
• Todrawdiagramsofnodeswillbeextremelyhelpful.• Whencopyingalinkedlist,onlycopyvaluestonewnodes.Donotcopypointers.
Doweneedtosearchtheentirelinked?
• Consideranascendingsorted(doublylinked)list:
• Doweneedtosearchthroughallthenodeswhenwe’researchingfor:
• 8• 50
• Awaytooptimizethesearch:sortedlistandearlystop
Howtoimplementanascendingsorted(doublylinked)list?• Changetheinsertion.Findthenodeq whosevalueisthegreatestlowerbound tothenewnodep.
• 1)Checkifhead’s valueislargerthanp’s.Ifso,insertp ashead.if (p -> value < head -> value) {
p -> next = head; head -> prev = p; p -> prev = NULL; head = p;
}
Howtoimplementanascendingsorted(doublylinked)list?• 2)ifnot,iteratethroughthelistuntilwefindthenodeq whosevalueisthegreatestlowerboundtop.
• Note:q->nextcaneitherhaveavaluelargerthanq,orisNULL.
Node *q = head -> next;while (q && q -> value < p -> value) {
if (q-> next == NULL || q -> next -> value > p -> value) break; q = q -> next;
}
Howtoimplementanascendingsorted(doublylinked)list?• 3)Insert pafterq:if(q->next!=NULL)q->next->prev =p;
p->next=q->next;/*ifqisthelastnodethenitsnextisalreadyNULL*/p->prev =q;q->next=p;
Insertintoanascendingdoublylinkedlistvoidinsert(Node*p,Node*head){if(p->value<head->value){p->next=head;head->prev =p;p->prev =NULL;head=p;return;
}Node*q=head->next;while(q->value<p->value){if(q->next==NULL||q->next->value>p->value)break;q=q->next;
}if(q->next!=NULL)q->next->prev =p;
p->next=q->next;p->prev =q;q->next=p;
}
Earlystopinsearchingasortedlinkedlist
• Westoptheiterationonceweseeanodewhichstoresavaluethatislargerthankey.
Node* Search(int key, Node* head){ Node *q = head;while(q != NULL && q -> value <= key) {
if(q -> value == key) return q; else q = q -> next; //iterate to the next node
} return NULL;
}
Whyearlystoptechniquesavescost
• Sparecostfromsearchtoinsertionandupdate• However,searchiscalledmassively,butinsertionandupdatenot.• O(n/2)costissavedforeachsearch(assumedatacomplieswithauniformdistribution)
ReverseLinkedList(Leetcode #206,easy)
Givenasinglylinkedlist,reverseeverynodeofit(i.e.eachnextpointstothepreviousnode).
Node*reverseList(Node*head)
Solution
Node* reverseList(struct ListNode* head) { Node *prev=NULL,*cur=head,*next; while(cur) {
next = cur->next; cur->next = prev; prev = cur;cur = next;
} return prev;
}