链表
/* typedef struct ListNode { int val; ListNode * next; }ListNode; */
链表初始化
在没有任何输入的情况下,我们首先需要定义一个头指针用来保存即将创建的链表。所以函数实现过程中需要在函数内定义并且申请一个结点的空间,并且在函数的结尾将这个结点作为新建链表的头指针返回给主调函数。
ListNode* list_init(){ ListNode* HeadNode = (ListNode*)malloc(sizeof(ListNode)); HeadNode->val = 0; HeadNode->next = NULL; return HeadNode; }
链表插入
void insert(ListNode* head,int pos,int x){ //实现将一个数据插入到链表的指定位置pos处 ListNode *p, *pre; pre = head; p = new node; //分配新结点 p->val = x; while(--pos){ //将pre指针定位到pos位置的前面 pre = pre->next; } p->next = pre->next; //先将pre的next赋值给p ,将pre所指结点后面所有的结点连接到p所指的结点 pre->next = p; //将p所指的结点链接到pre所指结点后面。 }
链表查找
int search(ListNode *head,int x){ //实现在链表中查找数据域等于x的结点的个数 int count=0; //计数器,初始化为零 ListNode* p = head->next; while(p != NULL){ if(p->val == x) //找到一个结点,计数器加一 count++; p=p->next; //p往后挪一个位置 } return count; //返回查找结果 }
链表删除
void del(ListNode *head,int x){ //实现将链表所有数据域等于x的结点删除 ListNode *pre,*p; pre = head; //pre指针始终指向被删除结点的前置结点 p = pre->next; //p指针为工作指针,用于遍历链表 while(p != NULL){ if(p->val == x){ //如果是要被删除的结点 pre->next = p->next; delete(p); //要记得用过的内存还给操作系统 p = pre->next ; //p指针更新到pre指针的后面 } else { pre=p; //如果不是要删除的结点那么两个指针分别后移,这一步该为pre=pre->next; p=p->next ; } }
链表创建
ListNode* creatlist(int arr[],int len){ //建立链表 ListNode *head,*pre,*p; head = new ListNode; //创造头结点 head->next = NULL; pre = head; //pre赋值 for(int i=0; i<len; i++){ p = new ListNode; p->data = arr[i]; //赋值给数据域 p->next = NULL; //最后一个节点的指针域置空 pre->next = p; //新结点连到链表的结尾 pre = p; //pre指向链表的最后一个结点 } return head; }
链表反转
输入:1 -> 2 -> 3 -> 4 -> 5
输出:5 -> 4 -> 3 -> 2 -> 1
//迭代 ListNode* listReverse(ListNode* head){ ListNode* newhead = NULL; ListNode* curr = head; while(curr){ temp = cur->next; //temp作为中间节点,记录当前结点的下一个节点的位置 cur->next = newhead; //当前结点指向前一个节点 newhead = cur; //指针后移 cur = temp; //指针后移,处理下一个节点 } return newhead; } //递归 ListNode * ReverseList(ListNode * head) { //递归终止条件:找到链表最后一个结点 if (head == NULL || head->next == NULL) return head; else { ListNode * newhead = ReverseList(head->next);//先反转后面的链表,从最后面的两个结点开始反转,依次向前 head->next->next = head;//将后一个链表结点指向前一个结点 head->next = NULL;//将原链表中前一个结点指向后一个结点的指向关系断开 return newhead; } }
-
curr 和 head 指向 1,tmp 指向 2, newhead指向空
-
将curr的next指向1(保存上一节点),newhead指向1
-
curr 和 tmp 整体向后移动一个节点
链表合并
按照链表中元素大小,从小到大合并链表
//迭代 ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { ListNode* res = new ListNode(0); ListNode* p = l1; ListNode* q = l2; ListNode* r = res; while(p && q){ if(p->val > q->val){ r->next = q; q = q->next; r = r->next; } else{ r->next = p; p = p->next; r = r->next; } } if(p) r->next = p; if(q) r->next = q; return res->next; } //递归 ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { if(l1 == NULL) return l2; else if (l2 == NULL) return l1; else if (l1->val < l2->val) { l1->next = mergeTwoLists(l1->next, l2); return l1; } else { l2->next = mergeTwoLists(l1, l2->next); return l2; } }
寻找链表的中间节点
1->2->3->4->5,返回3
1->2->3->4,返回中间的后一个,即3
//采用快慢指针 ListNode* middleNode(ListNode* head) { ListNode* fast = head; ListNode* slow = head; while(fast && fast->next){ fast = fast->next->next; slow = slow->next; } return slow; }
相交链表
-
暴力遍历
对链表A中的每一个结点Ai,遍历整个链表 B
并检查链表 B
中是否存在结点和Ai相同。
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { if(!headA || !headB) return nullptr; while (headA) { ListNode *temp = headB; if(headA == temp) return headA; while(!(temp -> next == NULL)) { temp = temp -> next; if(headA == temp) return headA; } headA = headA -> next; } return NULL; }
-
如果两个链表相交,那么相交点之后的长度是相同的
我们需要做的事情是,让两个链表从同距离末尾同等距离的位置开始遍历。这个位置只能是较短链表的头结点位置。 为此,我们必须消除两个链表的长度差
指针 pA 指向 A 链表,指针 pB 指向 B 链表,依次往后遍历 如果 pA 到了末尾,则 pA = headB 继续遍历 如果 pB 到了末尾,则 pB = headA 继续遍历 比较长的链表指针指向较短链表head时,长度差就消除了 如此,只需要将最短链表遍历两次即可找到位置
(1) pA->1->2->3->4->5->6->NULL
pB->5->6->NULL
(2) 1->pA->2->3->4->5->6->NULL
5->pB->6->NULL
(3) 1->2->pA->3->4->5->6->NULL
5->6->pB->NULL
此时pB指向B链表末尾,转而指向A链表表头
(4) pB->1->2->3->pA->4->5->6->NULL
5->6->NULL
(5)1-> pB->2->3->4->pA->5->6->NULL
5->6->NULL
(6)1->2-> pB->3->4->5->pA->6->NULL
5->6->NULL
(7) 1->2->3->pB->4->5->6->pA->NULL
5->6->NULL
此时pA指向A链表末尾,转而指向B链表表头
(8) 1->2->3->4->pB->5->6->NULL
pA->5->6->NULL
此时pA和pB指向共同节点,找到
若未找到,则pA和pB都会指向NULL
ListNode getIntersectionNode(ListNode* headA, ListNode* headB) { if (headA == NULL || headB == NULL) return NULL; ListNode* pA = headA, *pB = headB; while (pA != pB) { pA = pA == NULL ? headB : pA->next; pB = pB == NULL ? headA : pB->next; } return pA; }
判断回文链表
1->2->2->1
-
使用快慢指针找到链表中间节点
-
从中间节点之后,对链表后半段进行反转
-
比较链表前半段与后半段是否相同
bool isPalindrome(ListNode* head) { ListNode* fast = head; ListNode* slow = head; ListNode* mid = NULL; while(fast){ slow = slow->next; fast = fast->next? fast->next->next : fast->next; } while(slow){ ListNode* tmp = slow->next; slow->next = mid; mid = slow; slow = tmp; } while(head && mid){ if(head->val != mid->val) return false; head = head->next; mid = mid->next; } return true; }
移除链表节点
ListNode* removeElements(ListNode* head, int val) { if(head==NULL) return NULL; ListNode*H = new ListNode(-1); H->next = head; ListNode*p = H; ListNode*s =NULL; while(p->next!=NULL) if(p->next->val==val){ s= p->next; p->next = p->next->next; delete s; }else p = p->next; } return H->next; }
判断环形链表
使用快慢指针,快指针追上慢指针就说明有环
bool hasCycle(ListNode *head) { ListNode *faptr = head; ListNode *slptr = head; while(faptr != nullptr && faptr -> next != nullptr) { faptr = faptr -> next -> next; slptr = slptr -> next; if(faptr == slptr) return true; } return false; }