链表

0. 结构体及必要说明

1 typedef struct LNode {
2     int data;
3     struct LNode *next;
4 }*LinkList;

1. 设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点。

递归:head->next=return;

栈(head):将值不等于 x 的节点用栈收集起来,收集完成后重新连接即可。

 1 void del_x(LinkList &L,int x) {
 2     if(L==NULL)
 3         return;
 4     if(L.data==x) {
 5         LNode *temp=L;
 6         L=L->next;
 7         free(temp);
 8         del_x(L,x);
 9     } else
10         del_x(L->next,x);
11 }
12 /*递归*/
13 ListNode* removeElements(ListNode* head, int val) {
14     if (head == NULL)
15         return head;
16     head->next = removeElements(head->next, val);
17     return head->val == val ? head->next : head;
18 }
19 /*Java:栈*/
20 public ListNode removeElements(ListNode head, int val) {
21     Stack<ListNode> stack = new Stack<ListNode>();
22     while (head != null) {
23         if (head.val != val) {
24             stack.push(head);
25         }
26         head = head.next;
27     }
28     while (!stack.isEmpty()) {
29         stack.peek().next = head;
30         head = stack.pop();
31     }
32     return head;
33 }

ps:书上的答案是这样写的,但是我不太理解的是如果这样的话,那值为x的结点L虽然删除了,可L的前驱结点没能指向其后继结点整个单链不就断了吗...

     破案了!由于该单链表不带头结点,第六行L为调用该函数的外层L->next,故这里实现了L->next=L->next->next,可自行尝试删除一条单链表的第1、2、3...个结点。

2.在带头结点的单链表L中,删除所有值为x的结点,并释放其空间,假设值为x的结点不唯一,试编写算法以实现上述操作。

双指针遍历引用(pre,cur,temp):pre指向头结点,cur指向pre->next;

 1 void del_x(LinkList &L,int x) {
 2     LNode *cur=L->next,*pre=L,*temp;
 3     while(cur!=NULL) {
 4         //这里的if可以任意指定内容 
 5         if(cur->data==x) {
 6             temp=cur;
 7             cur=cur->next;
 8             pre->next=cur;
 9             free(temp);
10         } else {
11             pre=cur;
12             cur=cur->next;
13         }
14     }
15 }

3. L为带头结点的单链表,编写算法实现从尾到头反向输出每个结点的值。

递归:没啥好说的;

 1 void ReversePrint(LinkList L) {
 2     if(L->next!=NULL)
 3         ReversePrint(L->next);
 4     if(L!=NULL)//防止空链表的存在
 5         cout << L->data << endl;
 6 }
 7 /*带返回值*/
 8 vector<int> v;
 9 vector<int> ReversePrint(LinkNode *head) {
10     if(L==NULL)
11         return v;
12     ReversePrint(head);
13     v.push_back(head->data);
14     return v;
15 }

4.试编写在带头结点的单链表L中删除一个最小值结点的高效算法(假设最小值结点是唯一的)。

四指针遍历引用(pre,p,minpre,minp):先遍历,然后minpre->next=minp->next;

 1 LinkList DelMin(LinkList &L) {
 2     LNode *pre=L,*p=L->next;
 3     LNode *minpre=L,*minp=L->next;
 4     while(p!=NULL) {
 5         if(p->data<minp->data) {
 6             minpre=pre;
 7             minp=p;
 8         }
 9         pre=p;
10         p=p->next;
11     }
12     minpre->next=minp->next;
13     free(minp);
14     return L;
15 }

5.试编写算法将不带头结点的单链表就地逆置,所谓“就地”是指辅助空间复杂度为0(1)。

指针反转(pre,head,next):注意刚开始pre=NULL;

 1 //指针反转
 2 LinkList Reverse(LinkList &head) {
 3     ListNode *pre=NULL;
 4     ListNode *next;
 5     while(head) {
 6         next=head->next;
 7         head->next=pre;
 8         pre=head;
 9         head=next;
10     }
11     return pre;
12 }

6.有一个带头结点的单链表L,设计一个算法使其元素递增有序。

类似快排(pre,p,r):1、把pre,p置成一个链表,r置成一个链表;2、p作为后者的cur,r=p->head;在前者找到要插入的位置的前驱结点pre,把p插到pre后面。

 1 void Sort(LinkList &L) {
 2     LNode *p=L->next,*pre,*r=p->next;
 3     p->next=NULL;
 4     p=r;
 5     while(p!=NULL) {
 6         r=p->next;
 7         pre=L;
 8         /*找到要插入位置的前驱结点pre*/
 9         while(pre->next!=NULL&&pre->next->data<p->data)
10             pre=pre->next;
11         /*把p插到pre后面*/
12         p->next=pre->next;
13         pre->next=p;
14         /*p是另一条链表的cur*/
15         p=r;
16     }
17 }

7.请判断一个链表是否为回文链表。

栈(cur):把链表元素放进栈里,用栈顶元素和head进行验证。

 1 stack<int> s;
 2 bool isPalindrome(ListNode* head) {
 3     stack<int> s;
 4     ListNode *cur = head;
 5     while(cur) {
 6         s.push(cur->val);
 7         cur = cur->next;
 8     }
 9     while(head) {
10         if(head->val != s.top())
11             return false;
12         s.pop();
13         head = head->next;
14     }
15     return true;
16 }

8.链表相交

1 ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
2     ListNode *tempA=headA,*tempB=headB;
3     while(tempA!=tempB) {
4         tempA=(tempA==NULL)? headB:tempA->next;
5         tempB=(tempB==NULL)? headA:tempB->next;
6     }
7     return tempA;
8 }

9.删除任意链表中的重复元素

类似选择排序(cur,pre,next):双指针遍历(pre,next),遇到与cur相等值的元素改变指向。

 1 ListNode* deleteDuplicates(ListNode* head) {
 2     ListNode *cur = head;
 3     ListNode *pre = NULL;
 4     ListNode *next = NULL;
 5     while (cur != NULL) {
 6         pre = cur;
 7         next = cur->next;
 8         while (next != NULL) {
 9             if (cur->val == next->val) {
10                 pre->next = next->next;
11             } else {
12                 pre = next;
13             }
14             next = next->next;
15         }
16         cur = cur->next;
17     }
18     return head;
19 }

10.将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

1.如果两个链表中有一个为空,说明无须合并过程,返回另一个链表的头节点即可。

2.比较 head1 和 head2 的值,小的节点也是合并后链表的最小节点,这个节点无疑应该是 合并链表的头节点,记为 head。head 节点所在的链表为链表 1,另一个链表为链表 2。

3.  用cur1 和 cur2遍历,然后根据大小关系做出不同的调整(cur1 小于 cur2,不做调整,反之,让 pre 的 next 指针指向 cur2),同时用一个变量 pre 表示上次比较时值较小的节点。

4.  cur1先走完,就让pre->next接cur2;cur2先走完,散会!

 1 ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
 2     if(l1 == NULL || l2 == NULL)
 3         return l1==NULL? l2:l1;
 4     ListNode *head = l1->val < l2->val? l1 : l2;
 5     ListNode *cur1 = head == l1? l1 : l2;
 6     ListNode *cur2 = head == l1? l2 : l1;
 7     ListNode *pre = cur1;
 8     ListNode *next = NULL;
 9     while(cur1!=NULL && cur2!=NULL) {
10         if(cur1->val <= cur2->val) {
11             pre = cur1;
12             cur1 = cur1->next;
13         } else {
14             next = cur2->next;
15             pre->next = cur2;
16             cur2->next = cur1;
17             pre = cur2;
18             cur2 = next;
19         }
20     }
21     pre->next = cur1==NULL? cur2 : cur1;
22     return head;
23 }

11.给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

快慢指针(pre,cur):注意:如果有两个中间结点,pre->next是第二个中间结点,pre是第一个中间结点。

 1 ListNode* middleNode(ListNode* head) {
 2     /*当链表只有两个结点时*/
 3     if (head->next==NULL)
 4         return head;
 5     /*当链表只有两个结点时*/
 6     if (head->next->next == NULL) {
 7         return head->next;
 8     }
 9     ListNode *pre = head;
10     ListNode *cur = head;
11     while (cur->next != NULL && cur->next->next != NULL) {
12         pre = pre->next;
13         cur = cur->next->next;
14     }
15     /*如果有两个中间结点,pre->next是第二个中间结点,pre是第一个中间结点*/
16     return cur->next!=NULL? pre->next:pre;
17 }

12.给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。

 1 TreeNode* sortedListToBST(ListNode* head) {
 2     if(!head)
 3         return NULL;
 4     else if(!head->next)
 5         return new TreeNode(head->val);
 6     ListNode *pre=head,*cur=pre->next,*next=cur->next;
 7     while(next && next->next){
 8         pre=pre->next;
 9         cur=pre->next;
10         next=next->next->next;
11     }
12     pre->next=NULL;
13     TreeNode *root = new TreeNode(cur->val);
14     root->left = sortedListToBST(head);
15     root->right = sortedListToBST(cur->next);
16     return root;
17 }
原文地址:https://www.cnblogs.com/i-chase/p/13277312.html