Data structure and algorithm - linked list
Previous contents
1 - linked list
2-stack
3-queue
4-tree
5-fig
6-greedy algorithm
7-recursion and divide and conquer
8-sort
9 - query
10 - dynamic programming
11-STL Library
Basic concepts
Linear table: a finite sequence of zero or more elements
1, Storage structure of linear table
There are two storage structures of linear table: linear sequential structure and chain storage structure
1.1 sequential storage structure
//Define sequential storage linear tables #define MAXSIZE 20 / / define the maximum number of elements typedef int ElemType;//Define the type of data struct SqList { ElemType data[MAXSIZE]; int length;//Defines the current length of the linear table };
1.2 chain storage structure
//Storage structure of single linked list typedef int ElemType; struct Node { ElemType data;//Data domain Node *Next;//Pointer field }; //Defines the pointer to the node typedef Node* LinkList;
1.3 bidirectional linked list
typedef int ElemType; //2. Two way linked list typedef struct DulNode { ElemType data; DulNode *prior;//Pointer to precursor DulNode *next;//Pointer to successor }DulNode,*DuLinkList;
2, Basic operation
2.1 getting elements
Sequential storage structure (be sure to pay attention to boundary conditions)
/* Get element operation: bool GetElem(SqList L,int i,ElemType *e) Function: in the linear table L, transfer the value of the ith position to e Returns True if the delivery is successful and False if it fails */ bool GetElem(SqList L,int i,ElemType *e) { //Prevention of cross-border if(L.length==0 || L.length>MAXSIZE || i<1) { return false; } *e=L.data[i-1]; return true; }
Chain storage structure (pay attention to the second judgment condition)
/* Get element operation: bool GetElem(LinkList L,int i,ElemType *e) Function: in the linear table L, transfer the value of the ith position to e Returns True if the delivery is successful and False if it fails */ bool GetElem(LinkList L,int i,ElemType *e) { //Suppose there is a header node LinkList p=L->Next;//p points to the first node int j=1; while(p && j<i) { p=p->Next; ++j; } if(!p || j>i)//Cross border: 1 The linked list is empty, 2 The value of I is less than 0 { return false; } *e=p->data;//Gets the value of the ith position return true; }
2.2 insertion operation
Sequential storage
/* Insert operation: bool ListInsert(SqList *L,int i,ElemType e) Function: insert the value e at position i of linear table L, and return the bool type flag to judge whether the insertion is successful Assume that all elements move backward from the insertion point */ bool ListInsert(SqList *L,int i,ElemType e){ //Judge whether it is out of bounds if(L->length==MAXSIZE)//Judge whether the sequential linear table is full { return false; } if(i<1|| i>L->length+1) { return false; } if(i<L->length)//If it is not at the end of the table, other elements need to vacate their current position { for(int k=L->length-1;k>i-1;k--)//From the value of the current position k, move backward in turn { L->data[k+1]=L->data[k];//To start with the last digit at the end, borrow and move forward from the back. Wrong writing method: L - > data [k] = L - > data [k-1]; } } L->data[i-1]=e; L->length++; return true; }
Linked Storage
/* Insert operation: bool ListInsert(LinkList *L,int i,ElemType e) Function: insert the value e at position i of linear table L, and return the bool type flag to judge whether the insertion is successful Assume that all elements move backward from the insertion point */ bool ListInsert(LinkList *L,int i,ElemType e){ LinkList p,s; p=*L; int j=1; while(p && j<i) { p=p->Next; ++j; } if (!p || j>i) { return false; }//p points to the position of i-1 //Request memory space s=(LinkList)malloc(sizeof(Node)); s->data=e; s->Next=p->Next; p->Next=s; return true; }
2.3 deleting
Sequential storage (elements need to be moved in all locations except the last location)
/* Delete operation: bool LisDelete(SqList *L,int i,ElemType *e) Function: delete the i-th digit in the L-order linear table, store the deleted value in (* e), and return the bool type flag to judge whether the deletion is successful */ bool LisDelete(SqList *L,int i,ElemType *e) { if(L->length==0)//Remember, don't forget this condition { return false; } if(i<1 && i>L->length) { return false; } *e=L->data[i-1]; if(i<L->length) { for(int k=i-1;k<L->length;k++) { L->data[k]=L->data[k+1]; } } L->length--; return false; }
Linked Storage
/* Delete operation: bool LisDelete(LinkList *L,int i,ElemType *e) Function: in the ith digit of L linear table, delete the element, store the deleted value in (* e), and return the bool type flag to judge whether the deletion is successful */ bool LisDelete(LinkList *L,int i,ElemType *e) { LinkList p,s; p=*L;//Head node int j=1; while(p && j<i) { p=p->Next; j++; } if(!(p) || j>i) { return false; }//Point to the i-1 element s=p->Next; p->Next=s->Next; *e=s->data; free(s);//Reclaim free memory return true; }
2.4 head insertion and tail insertion of linked list
The head interpolation method is relatively simple, and the tail interpolation method requires additional pointers to record the tail nodes
//Head node pointer: the node with empty data field: first generate the node with malloc function, and then define the next pointer field as empty, without assigning value to the data. /* Creation of single linked list and whole table 1: header insertion method Randomly generate the values of n elements and establish a single linear linked list L Create a single linear linked list: void createListHead(LinkList *L,int n) n Represents the length of the linear table */ void createListHead(LinkList *L,int n) { LinkList p; int i; //Define a random number seed //srand(time(0)); *L=(LinkList)malloc(sizeof(Node)); (*L)->Next=NULL;//First, create an empty single linked list with a header node for(int i=0;i<n;i++) { //Create node and apply for memory p=(LinkList)malloc(sizeof(Node)); p->data=i;//input data //Just link each node p->Next=(*L)->Next;//The current node refers to the original node of the head node, which is equivalent to inserting the current node between the head node and the original node (*L)->Next=p;//The header points to the current node } } //First, use malloc function to generate a header, execute the node link of the loop in the middle, and point the next pointer of the tail node to null in the last sentence of the function /* Creation of single linked list and whole table 2: tail interpolation Randomly generate the values of n elements and establish a single linear linked list L Create a single linear linked list: void createListTail(LinkList *L,int n) n Represents the length of the linear table */ void createListTail(LinkList *L,int n) { LinkList p,s; int i; //Define a random number seed //srand(time(0)); *L=(LinkList)malloc(sizeof(Node)); //(*L)->Next=NULL;// A single node with an empty list header is created first p=*L; for(int i=0;i<n;i++) { //Create node and apply for memory s=(LinkList)malloc(sizeof(Node)); s->data=i;//input data p->Next=s; //s->Next=NULL; p=s; } s->Next=NULL;//The tail node is empty }
2.5 deletion of linked whole table
/* Delete the whole table of single linked list: */ bool ClearList(LinkList *L) { LinkList p,s; p=(*L)->Next;//Point to the first node //Recycle node pointer while(p) { s=p->Next; free(p); p=s; } //Recycle head pointer (*L)->Next=NULL; return true; }
3, Leetcode brush questions
2.1 construction
structure
struct ListNode{ int val; ListNode *next; };
Simple construction method
ListNode a(1); ListNode b(4); ListNode c(6); ListNode d(0); ListNode e(5); ListNode f(7); a.next = &b; b.next = &c; d.next = &e; e.next = &f; f.next=nullptr; ListNode *head=&a;//Head node pointer
2.2 reverse linked list
leetcode 206 - reverse linked list
Idea: Double pointers, one pointing to the head node of the reverse chain (initialized to null, just forming the conversion), and the other recording the next node of the head node. (head pointer, front position of head pointer, next position of head pointer)
class Solution { public: ListNode* reverseList(ListNode* head) { //Double pointer ListNode * new_head=nullptr; ListNode * next=nullptr; while(head) { next=head->next; head->next=new_head; new_head=head; head=next; } return new_head; } };
2.3 reverse linked list 2
leetcode 92 - reverse linked list
Idea: 1 Note the saving of four location nodes, 2 Note the returned header node 3 Pay attention when using while++
class Solution { public: ListNode* reverseBetween(ListNode* head, int left, int right) { ListNode *lpr_ptr=nullptr; ListNode *lptr=head; ListNode * rpr_ptr=nullptr; ListNode * rptr=nullptr; for(int i=1;i<left;i++) { lpr_ptr=lptr; lptr=lptr->next; } rpr_ptr=nullptr; rptr=lptr; for(int i=left;i<right+1;i++) { ListNode *temp=rptr->next; rptr->next=rpr_ptr; rpr_ptr=rptr; rptr=temp; } //Splice data if(lpr_ptr)//Special case handling { lpr_ptr->next=rpr_ptr; lptr->next=rptr; } else { lptr->next=rptr; head=rpr_ptr; } return head; } };
2.2 and 2.3 summary of two questions: when reversing the linked list, you need to have three pointers to save the address of the current node precursor (initialized as nullptr), the current node address (the default is the header pointer address) and the subsequent address (to avoid loss),
2.4 find the intersection of two linked lists
leetcode 160 intersecting linked list
Idea 1: violence solution, define two vector containers, traverse the linked list a and b respectively, store all nodes in the corresponding container respectively, and then traverse from back to front until unequal nodes are found, and return to the previously saved nodes. (Note: 1. Write ';', 2. Remember to write + + operations in the while loop, otherwise it will lead to an endless loop)
class Solution { public: ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { vector<ListNode *> vec_A; vector<ListNode *> vec_B; ListNode *p=headA; while(p) { vec_A.push_back(p); p=p->next; } p=headB; while(p) { vec_B.push_back(p); p=p->next; } int i=vec_A.size()-1; int j=vec_B.size()-1; p=nullptr; while(i>=0 && j>=0 && vec_A[i]==vec_B[j]) { p=vec_A[i]; i--; j--; } return p; } };
Idea 2: first traverse all the nodes in the A-linked list, save all the nodes in the A-linked list in a set set, and then traverse all the nodes in B. each time, check whether the node is in the set set. If the node is returned, Otherwise, nullptr is returned (Note: the operation of adding elements to set is insert, not push_back. In addition, set has its own find method, and vector does not have its own find method).
class Solution { public: ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { //Use the set set to find the first identical pointer address set<ListNode *> node_set; ListNode *pnode=headA; while(pnode) { node_set.insert(pnode); pnode=pnode->next; } pnode=headB; while(pnode) { if(node_set.find(pnode)!=node_set.end()) { return pnode; } pnode=pnode->next; } return nullptr; } };
Idea 3: for the common part, you can first align the linked list, that is, first traverse from the longer linked list to the location of the shorter linked list, and then traverse synchronously until the same common location is found. Note: the space complexity is O(1)
class Solution { int getListLen(ListNode *head)//Find the length of the array { int len=0; while(head) { len++; head=head->next; } return len; } public: ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { int lenA=getListLen(headA); int lenB=getListLen(headB); if(lenA>lenB) { for(int i=0;i<lenA-lenB;i++) { headA=headA->next; } } else { for(int i=0;i<lenB-lenA;i++) { headB=headB->next; } } while(headA && headB) { if(headA==headB) return headA; headA=headA->next; headB=headB->next; } return NULL; } };
2.5 link calculation of linked list
Leetcode-141 circular linked list
Leetcode-142 circular linked list 2
Idea 1: the idea of set. Each time you traverse a node, you first judge whether it is in the set. If it is not added to the set, otherwise it is a ring linked list. When you traverse an empty node, you return No.
class Solution { public: bool hasCycle(ListNode *head) { ListNode *nodePtr=head; set<ListNode *> nodeSet; while(nodePtr) { if(nodeSet.find(nodePtr)!=nodeSet.end())//Is there a node in the collection { return true; } nodeSet.insert(nodePtr); nodePtr=nodePtr->next; } return false; } };
Idea 2: the fast and slow pointer points to the head node with two pointers. One takes one step and the other takes two steps. The fast pointer catches up with the slow pointer. It is a circular linked list. The fast pointer goes to the empty node, not a circular linked list
class Solution { public: bool hasCycle(ListNode *head) { ListNode *fast=head;//fast ListNode *slow=head;//slow while(fast) { fast=fast->next; slow=slow->next; if(fast==nullptr) { break; } fast=fast->next; if(fast==slow) return true; } return false; } };
Circular linked list 2
class Solution { public: ListNode *detectCycle(ListNode *head) { //Fast and slow pointer method, ferrule method a+b+c+b=2*(a+b) therefore, a=c, starting from points a and c at the same time, the meeting point is the entrance of the ring ListNode * fast=head; ListNode * slow=head; ListNode * meet=nullptr; while(fast) { //Go first fast=fast->next; slow=slow->next; if(!fast) return nullptr; fast=fast->next;//Come on, take two steps if(fast==slow) { meet=fast; break;//Remember to jump out of the loop } } while(meet && head) { if(meet==head) return head; meet=meet->next; head=head->next; } return nullptr; } };
2.6 split linked list
Leetcode-86 split linked list
Idea: create two empty header pointers, compare the elements of each node, use the tail insertion method, insert the corresponding elements into the two linked lists, splice the data, and set the tail pointer to nullptr, = = (if nodeptr - > next operation is on the left of the equal sign, remember to back up the data pointed to)==
class Solution { public: ListNode* partition(ListNode* head, int x) { ListNode small_head(0); ListNode big_head(0); //Tail difference method - tail pointer ListNode *small_end_ptr=&small_head; ListNode *big_end_ptr=&big_head; //Move pointer ListNode *nodePtr=head; while(nodePtr) { if(nodePtr->val<x) { small_end_ptr->next=nodePtr;//Tail interpolation data small_end_ptr=nodePtr; } else { big_end_ptr->next=nodePtr; big_end_ptr=nodePtr; } nodePtr=nodePtr->next; } small_end_ptr->next=big_head.next; big_end_ptr->next=nullptr; return small_head.next; } };
2.7 merge two ordered linked lists
Leetcode-24 combines two ordered linked lists
Idea: create an empty head node, traverse the two linked lists respectively and add them to the new linked list. Due to the need to sort from small to large, the tail insertion method needs a new pointer to record the position of the tail node, and finally point the next pointer field of the tail node to NULL;
Clever use of head null pointer
class Solution { public: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { ListNode new_head(0); ListNode *lastPtr=&new_head; while(l1 && l2) { if(l1->val <l2->val) { //l1 join lastPtr->next=l1; lastPtr=l1; l1=l1->next; } else { lastPtr->next=l2; lastPtr=l2; l2=l2->next; } } if(l1) { lastPtr->next=l1; } else { lastPtr->next=l2; } return new_head.next; } };
2.8 merge K ascending linked lists
Leetcode-23 merge K ascending linked lists
Idea: divide the list merging problem in lists into the first half and the second half, and then divide the sub problems. Know that it is divided into the list merging problem, divide and rule it.
class Solution { public: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {//Code for merging linked lists ListNode new_head(0); ListNode *lastPtr=&new_head; while(l1 && l2) { if(l1->val <l2->val) { //l1 join lastPtr->next=l1; lastPtr=l1; l1=l1->next; } else { lastPtr->next=l2; lastPtr=l2; l2=l2->next; } } if(l1) { lastPtr->next=l1; } else { lastPtr->next=l2; } return new_head.next; } ListNode* mergeKLists(vector<ListNode*>& lists) { if(lists.size()==0) return nullptr; if(lists.size()==1) return lists[0]; if(lists.size()==2) return mergeTwoLists(lists[0],lists[1]); int mid=lists.size()/2; vector<ListNode *> sub1_lists; vector<ListNode *> sub2_lists; for(int i=0;i<mid;i++) { sub1_lists.push_back(lists[i]); } for(int i=mid;i<lists.size();i++) { sub2_lists.push_back(lists[i]); } ListNode *l1=mergeKLists(sub1_lists);//First half: divide and conquer 1 ListNode *l2=mergeKLists(sub2_lists);//Second half: divide and Conquer 2 return mergeTwoLists(l1,l2); } };
come on.