• 链表


    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 }
  • 相关阅读:
    JAVA-基础-网络通信协议
    JAVA-基础-线程安全
    JAVA-基础-多线程
    IDEA安装破解JFrameDesigner
    windows IIS安装memadmin
    exe应用程序安装为windows服务
    远程管理virtual box的几种方式
    手动修改注册表更改MAC地址
    在火狐插件中使用socket编程与java进行通信
    定制自己的firefox插件并在selenium中使用
  • 原文地址:https://www.cnblogs.com/i-chase/p/13277312.html
Copyright © 2020-2023  润新知