链表应用题

1. 递归删除指定值(无头结点)

void Del(ListNode* L,int val){
    ListNode* p;//指向被删除节点
    if(L==NULL) return;//递归边界
    if(L->val==val){//处理首指针
        p = L;
        L = L->next;
        free(p);//删除节点
        Del(L,val);//递归调用
    }
    else Del(L->next,val);//递归调用
}

2. 循环删除指定值(有头结点)

void Del(ListNode* L,int val){
    ListNode* p = L->next;//遍历节点
    ListNode* pre = L;//辅助删除节点
    ListNode* q;//删除节点
    while(p!=NULL){//遍历节点存在
        if(p->val==val){//找到指定值,更改指针结构
            q = p;
            p = p->next;
            pre->next = p;
            free(q);
        }
        else{
            pre = p;
            p = p->next;
        }
    }
}

3. 反向输出每个值(有头结点)

//主函数从头结点下一个节点调用函数
void rprint(ListNode* L){
    if(L->next) rprint(L->next);//入栈
    print(L->val);
}

4. 删除最小值(有头结点)

void del_min(ListNode* L){
    ListNode* pre = L;  ListNode* p = pre->next;
    ListNode* minpre = pre; ListNode* minp = p;
    while(p){
        if(p->val<minp->val){
            minp = p;
            minpre = pre;
        }
        pre = p;
        p = p->next;
    }
    minpre->next = minp->next;
    free(minp);
}

5. 就地逆置(有头结点)

ListNode* reverseList(ListNode* head) {
    ListNode*pre= head;
    head = head->next;
    ListNode*node;//插入节点
    while(head){
        node = head;
        head = head->next;
        node->next = pre->next;
        pre->next = node;
    }
    return pre;

6. 递增有序(有头结点)

void sort(ListNode* head){
    ListNode* p = head->next;//遍历节点
    head->next = NULL;//断链
    ListNode* node;//插入节点
    while(p){
        node = p;
        p = p->next;
        insert(head,node);//插入重构链表
    }
}

void insert(ListNode* pre,ListNode* node){//将node插入到头结点为pre的链表中
    while(pre->next&&pre->next->val<node->val)
        pre = pre->next;//找到插入位置的前驱
    node->next = pre->next;
    pre->next = node;
}

7. 删除指定范围值(与题2基本一致)

8. 求两链表公共节点(相交链表)

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;
}

9. 递增输出并释放(循环调用题4函数)

10. 按奇偶拆分

ListNode * split(ListNode *A){
    int i =0;//判断序号
    ListNode * B = new ListNode();
    ListNode * ra = A, rb = B;//链表遍历指针
    ListNode *p = A->next;//拆分A的遍历指针
    while(p){//每次处理一个元素
        i++;
        if(i%2==0) rb->next=p,rb=p;//更改下条件可以用来处理奇数偶数
        else ra->next=p,ra=p;
        p = p->next;
    }
    ra->next = NULL;
    rb->next = NULL;
    return B;
}

11. 按奇偶拆分(奇尾插、偶头插)

12. 递增有序去重

void Del_same(ListNode* head){
    ListNode* p = head->next;//遍历指针
    if(p==NULL) return;
    while(p->next){//下一节点存在
        ListNode* q = p->next;
        if(p->val==q->val){//删除节点
            p->next = q->next;
            free(q);
        }
        else p = p->next;
    }
}

13. 合并两升序链表并反转

ListNode* mergeTwoLists(ListNode* l1, ListNode* l2){
   ListNode* p1 = l1->next;
   ListNode* p2 = l2->next;
   l1->next = NULL;//l1作为返回值,原地修改
   ListNode* r;//记录辅助插入
   while(p1&&p2){
       if(p1->val<=p2->val){//头插较小值
          r = p1;
          p1 = p1->next;
          r->next = l1->next;
          l1->next = r;
       }
       else{//一样操作
          r = p2;
          p2 = p2->next;
          r->next = l1->next;
          l1->next = r; 
       }
   }
   if(p2) p1 = p2;//统一操作
   //处理剩下的链表
   while(p1){
      r = p1;
      p1 = p1->next;
      r->next = l1->next;
      l1->next = r;
   }
   return l1;
}

14. 产生公共链表

//每次移动较小元素直到找到公共部分
     ListNode* common(ListNode* l1, ListNode* l2){
         ListNode*p = l1->next;
         ListNode*q = l2->next;//遍历节点
         ListNode* l3 = new ListNode();
         ListNode* r = l3;//尾插遍历节点
         while(p&&q){
             if(p->val<q->val) p = p->next;
             else if(p->data>q->data) q = q->next;
             else{
                ListNode* s = new ListNode(p->val);//复制节点信息
                r->next = s;
                r = r->next;//尾插复制节点
                p = p->next;
                q = q->next;
             }
         }
     }

15. 求链表交集(与题14基本一致)

16. 判断连续子序列

 bool Pattern(ListNode* l1, ListNode* l2){
     //也可以通过遍历l1,回溯l2的形式来实现
     if(l1==NULL) return false;//边界条件一
     if(l2==NULL) return true//边界条件二
     if(l1->val==l2->val) return Pattern(l1->next,l2->next)|Pattern(l1->next,l2);
     else Pattern(l1->next,l2);
 }

17. 判断循环双链表对称(有头结点)

bool Symmetry(ListNode* L){
     ListNode* p = L->next;
     ListNode* q = L->prior;
     while(p!=q&&q->next!=p){
         if(p->val==q->val){
             p = p->next;
             q = q->prior;
         }
         else return false;
     }
     return true;

18. 串联两循环单链表

ListNode* Symmetry(ListNode* l1,ListNode*l2){
   ListNode* p = l1;
   ListNode* q = l2;//遍历找尾结点
   while(p->next!=l1) p = p->next;
  while(q->next!=l2) q = q->next;
  //更改结构
  p->next = l2;
  q->next = l1;
  return l1;

19. 重复删除循环单链表最小值

//与不循环的只是判空和遍历结束条件不同
ListNode* Del(ListNode* L){
  ListNode* p,*pre,*minp,*minpre;
  while(L->next!=L){//重复查找删除至空
      p = L->next; pre = L;
      minp = p; minpre = pre;
      while(p!=L){//遍历全链表
          if(p->val<minp->val){
              minp = p;
              minpre =pre;
          }
          pre = p;
          p = p->next;
      }
      //输出最小值minp->val
      minpre->next = minp->next;
      free(minp);
  }
}

20. 双链表按频递减

ListNode* Locate(ListNode* L,int val){
  ListNode* p = L->next;//遍历节点
  while(p&&p->val!=val)
      p = p->next;//找对应节点
  if(!p) exit(0);//不存在该节点,查找失败

  p->freq++;//频率加
  if(p->next) p->next->prior = p->prior;//摘除该节点
  p->prior->next = p->next;
  ListNode* q = p->prior;//往前遍历节点
  while(q!=L&&q->freq<=p->freq)
      q = q->prior;
  //将p插入q的后面
  p->next = q->next;
  q->next = p;
  p->prior = q;
  p->next->prior = p;
}

21. 倒数第k个节点

快慢指针

ListNode* getKthFromEnd(ListNode* head, int k) {
    ListNode* p1 =head;
    ListNode* p2 =head;
    for(int i=0;i<k;i++) p2=p2->next;
    while(p2){
        p1=p1->next;
        p2=p2->next;
    }
    return p1;
}

22. 字符链表的公共节点(相交链表)与题8等同

23. 删除绝对值重复节点

数组做哈希表,其他操作与删除指定元素一样

void Del(ListNode* L){
    ListNode* p = L->next;//遍历节点
    ListNode* pre = L;//辅助删除节点
    ListNode* q;//删除节点
    int* hash = (int*)malloc(sizeof(int)*(n+1));//哈希表
    memset(hash,0,sizeof(int)*(n+1));//初始化为0
    while(p){//遍历节点存在
        if(hash[abs(p->val)]==0){//没出现过该元素绝对值,后移
            pre = p;
            p = p->next;
        }
        else{//否则删除该值
            q = p;
            p = p->next;
            pre->next = p;
            free(q);
        }
        hash[abs(p->val)]++;
    }
}

24. 找环的入口

先快慢指针找相遇位置,此时快指针距离是慢指针两倍,它们的差同样也是环的n倍
可知慢指针已经走了环的n倍距离,此时通过重置快指针,让慢指针再走环外距离,使其到达环的入口处

//快慢指针
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode * fast = head;
        ListNode * slow = head;
        while(true){
            if(!fast||!fast->next) return NULL;
            slow = slow->next;
            fast = fast->next->next;
            if(slow==fast) break;
        }
        fast = head;
        while(fast!=slow)
            fast=fast->next,slow=slow->next;//slow在循环中转圈
        return fast;
    }
};

25. 重排链表

排列成(1,n,2,n-1,3,n-2...)的形式
快慢指针找中点,逆置中点后链表,再依次插入

    ListNode* change(ListNode* head) {
        ListNode* slow = head;
        ListNode* fast = head;
        while (fast->next) {
            slow = slow->next;
            fast = fast->next;
            if(fast->next) fast = fast->next;
        }
        fast = slow->next;//fast指向后半段链表
        slow->next = NULL;//断链
        while(fast){//逆置后半段链表
            ListNode* r = fast;//辅助插入节点
            fast = fast->next;
            r->next = slow->next;//slow作为头进行头插
            slow->next = r;
        }
        ListNode* s = head->next;//插入点,插入其后
        fast = slow->next;//重置fast为后半第一个节点
        slow->next = NULL;//断链

        while(fast){
            ListNode* r = fast;//辅助插入节点
            fast = fast->next;
            r->next = s->next;
            s->next = r;
            s = r->next;//跳一个位置
        }
    }
posted @ 2022-08-20 19:53  失控D大白兔  阅读(27)  评论(0编辑  收藏  举报