删除双向循环列表的共同节点

第二章、删除双向循环列表的共同节点

1、面试题目

36、有双向循环链表结点定义为:

 

struct node

 

{

   int data;

 

   struct node *front,*next;

 

};

 

有两个双向循环链表A,B,知道其头指针为:pHeadA,pHeadB,请写一函数将两链表中

data 值相同的结点删除。

2、解题方法

2.1、暴力求解

2.1.1 思路

1、对于链表A中的每一个元素Ai, 查看Ai是否在链表B中,若存在则在A,B链表中删除Ai,否则继续查看下一个元素直到结束。

2、时间复杂度O(m*n),其中m为链表A的长度,n为链表B的长度;

2.1.2 测试代码

#include <iostream>

#include <algorithm>

#include <bitset>

using namespace std;

 

#define NSIZ 1000000

 

36、有双向循环链表结点定义为:

struct node

{

   int data;

   struct node *front,*next;

};

有两个双向循环链表A,B,知道其头指针为:pHeadA,pHeadB,请写一函数将两链表中

data 值相同的结点删除。

 

typedef struct Node_

{

         intdata;

         Node_* front, *next;

}Node;

 

void print(Node * head)

{

         if(!head)

         {

                   printf("链表为空!!!\n");

                   return;

         }

 

         Node* p = head;

         do

         {

                   printf("%d", p->data);

                   p= p->next;

         }while(p!= head);

 

         printf("\n");

}

 

//创建链表

Node * CreateList(int arr[], int n)

{

         Node* head = 0, * p = 0;

         inti;

 

         if(head== 0)

         {

                   head= new Node();

                   head->data= arr[0];

                   head->front= head;

                   head->next= head;

                   p= head;

         }

 

         for(i= 1;i < n; ++i)

         {

                   Node* tmp = new Node();

                   tmp->data= arr[i];

        

                   tmp->next= p->next;

                   p->next= tmp;         

                  

                   tmp->front= p;        

                   p= tmp;

         }

         head->front= p;

         returnhead;

}

 

//若列表中剩下最后一个节点,删除后返回0

//若删除节点不是最后一个节点1)若非头结点,则直接返回该节点的下一个节点;2)若是头结点,调节头结点为下一个节点

Node* DeleteNode(Node * p, Node *&head)

{

 

         if(p->next== p) //链表中只有一个节点

         {

                   deletep;

                   p= 0;

                   head= p;

                   return0;

         }

 

         Node* p_next = p->next;

         p->front->next= p->next;

         p->next->front= p->front;

        

        

         if(p== head)

         {

                   head= p->next;

         }

 

         if(p)

         {

                   deletep;

                   p= 0;

         }

         returnp_next;

}

 

//算法1,对A链中的每一个元素在B链中寻找,若存在则删除,时间复杂度O(M*N)

// M, N 分别为链表A,B的长度

void DeleteCommonNode(Node * &head1,Node * &head2)

{

         if(!head1|| !head2 )

         {

                   return;

         }

         printf("删除相同节点:");

         Node* p1 = head1, *p2 = head2;

        

         intfind = 0;

         intend = 0;

         do

         {

                   find= 0;

                   p2= head2;

                  do

                   {

                            if(p1->data== p2->data)

                            {

                                     find= 1;

                                     break;

                            }

                            p2= p2->next;

 

                   }while(p2&& p2 != head2);

 

                   if(find== 1)//找到相同节点

                   {

                            printf("%d", p1->data);

                            p1= DeleteNode(p1, head1);

                            p2= DeleteNode(p2, head2);

                           

                            if(head2== 0 || head1 == 0)

                            {

                                     break;

                            }

                   }

                   else//未找到相同节点

                   {

                            p1= p1->next;

                            end++;

                   }

 

         }while(p1&& (p1 != head1 || (end <= 1 && p1 == head1)));

 

         printf("\n\n");

 

}

 

int main()

{

         intarr[] = {1, 2, 3};

         intan = sizeof(arr)/sizeof(arr[0]);

        

         Node* head1 = CreateList(arr, an);

         printf("链表A的元素: ");

         print(head1);

 

 

         intbrr[] = {1, -1, 2, 3};

         intbn = sizeof(brr)/sizeof(brr[0]);

 

         Node* head2 = CreateList(brr, bn);

         printf("链表B的元素: ");

         print(head2);

 

         DeleteCommonNode(head1,head2);

 

 

         printf("删除相同节点后再次遍历链表:\n");

         printf("删除公共节点后链表A的剩下元素:");

         print(head1);

         printf("删除公共节点后链表B的剩下元素:");

         print(head2);

 

         return0;

}

2.2使用Bitmap

2.2.1 思路

思路:

使用辅助变量bitmap,主要针对A,B集合中的元素在某一个范围内比如1-10^9,使用bitmap,一个bit表示一个数。

1)  首先遍历链表A和链表B, 把最大值maxD =max(maxA, maxB)和最小值minD = min(mina, minB)找出来,maxA是A链表中的最大值,maxB是B链表的最大值,同理minA是A链表中的最小值,minB是B链表的最小值;申请bitset空间时,如果minD<0, 那么bitset大小为maxD+abs(mind) +1,若果minD>=0,那么bitset大小为maxD;

2)  再次遍历A链表,把相应的bitset[A[i]]为置为1;

3)  再次遍历B链表,把bitset[B[i]]为1的元素放到向量或者数组C中,数组C中元素就是链表A和B中公共元素;

4)  Bitset全部重置,遍历数组C,把相应的bitset[C[i]]置为1;

5)  第三次遍历A链表,B链表,把bitset[A[i]]= 1,bitset[B[i]]=1的结点删掉;

6)  结束;

上述整个过程展现了一个在O(m+n)的时间复杂度内解决的法案,但是上述过程是可以继续优化的,比如

Ø  如果题目给定链表A和B的元素范围已经清晰知道,步骤1)中就不用遍历找最大值和最小值了;

Ø  步骤3)可以根据bitset[B[i]]=1把B链表中的公共结点删除,就不用在步骤5)再次链表B了;

你懂得,这里只是展示了一种O(m+n)思想,m为链表A的长度,B为链表B的长度;

2.2.2 测试代码

#include <iostream>

#include <algorithm>

#include <bitset>

using namespace std;

 

#define NSIZ 100000

 

typedef struct Node_

{

         intdata;

         Node_* front, *next;

}Node;

 

bitset<NSIZ> bs; //bitset,一个bit表示一个数

int arr[NSIZ];

int brr[NSIZ];

int crr[NSIZ];

 

int minD = 0, maxD = 0; //minD表示链表A和链表B的中最小值,maxD表示链表A和链表B的中最大值

 

//打印链表

void print(Node * head)

{

         if(!head)

         {

                   printf("链表为空!!!\n");

                   return;

         }

 

         Node* p = head;

         do

         {

                   printf("%d", p->data);

                   p= p->next;

         }while(p!= head);

 

         printf("\n");

}

 

//创建链表

Node * CreateList(int arr[], int n)

{

         Node* head = 0, * p = 0;

         inti;

 

         if(head== 0)

         {

                   head= new Node();

                   head->data= arr[0];

                   head->front= head;

                   head->next= head;

                   p= head;

         }

 

         for(i= 1;i < n; ++i)

         {

                   Node* tmp = new Node();

                   tmp->data= arr[i];

        

                   tmp->next= p->next;

                   p->next= tmp;         

                  

                   tmp->front= p;        

                   p= tmp;

         }

         head->front= p;

         returnhead;

}

 

//若列表中剩下最后一个节点,删除后返回0

//若删除节点不是最后一个节点1)若非头结点,则直接返回该节点的下一个节点;2)若是头结点,调节头结点为下一个节点

Node* DeleteNode(Node * p, Node *&head)

{

 

         if(p->next== p) //链表中只有一个节点

         {

                   deletep;

                   p= 0;

                   head= p;

                   return0;

         }

 

         Node* p_next = p->next;

         p->front->next= p->next;

         p->next->front= p->front;

        

        

         if(p== head)

         {

                   head= p->next;

         }

 

         if(p)

         {

                   deletep;

                   p= 0;

         }

         returnp_next;

}

 

//遍历整个链表

int GetNode(Node * head, int arr[], int&len, int &minD, int &maxD)

{

         if(head== 0)

         {

                   return0;

         }

         len= 0;

         Node* p = head;

         minD= p->data;

         maxD= p->data;

         arr[len++]= p->data;

         p= p->next;

        

         while(p!= head)

         {

                   arr[len++]= p->data;

 

                   if(p->data> maxD)

                   {

                            maxD= p->data;

                   }

 

                   if(p->data< minD)

                   {

                            minD= p->data;

                   }

 

                   p= p->next;

         }

 

         returnlen;

}

首先遍历链表A和B获得数组A和数组B以及最大值maxD和最小值minD

//然后遍历数组A,对bitset[A[i]]进行置为1

//然后遍历数组B,把bitset[B[i]]为1的元素放到数组C中,C数组即为公共元素数组

//把bitset重置为0,再次遍历数组C, bitset[C[i]]置为1

void Common(Node * head1, Node * head2)

{

 

         intan = 0, bn = 0;

         inti = 0, cn = 0;

 

         intminA = 0, maxA = 0;

         intminB = 0, maxB = 0;

 

 

         GetNode(head1,arr, an, minA, maxA);

         GetNode(head2,brr, bn, minB, maxB);

         minD= min(minA, minB);

         maxD= max(maxA, maxB);

 

 

         bs.reset();

 

         //当最小值大于等于0时,统一为0

         if(minD>= 0)

         {

                   minD= 0;

         }

 

 

         for(i= 0;i < an; ++i)

         {

                   bs[arr[i]-minD] = 1;

         }

 

         printf("删除相同节点:");

         for(i= 0;i < bn; ++i)

         {

                   if(bs[brr[i]- minD])

                   {

                            crr[cn++]= brr[i];

                            printf("%d", brr[i]);

                   }

         }

 

         bs.reset();

         for( i = 0;i < cn;++i)

         {

                   bs.set(crr[i]-minD);

         }

 

 

}

 

 

//先求出两个链表公用节点,

//然后分别遍历两个链表A和B把bitset[A[i]]= 1和bitset[B[i]] = 1的节点分别删除之

void DeleteCommonNode(Node * &head1,Node * &head2)

{

         if(!head1|| !head2 )

         {

                   return;

         }

 

         //获得两个链表中的公共的节点

         Common(head1,head2);

        

         Node* p1 = head1, *p2 = head2;

         intend = 0;

 

         //删除链表A中公共节点

         do

         {

                   if(bs[p1->data- minD] == 1)

                   {

                            p1= DeleteNode(p1, head1);

                   }

                   else

                   {

                            p1= p1->next;

                            if(p1== head1)

                            {

                                     end++;

                            }

                   }

 

         }while(p1&&(p1 != head1 || (end <= 1 && p1 == head1)));

        

         end= 0;

         //删除链表B中公共节点

   do

         {

                   if(bs[p2->data- minD] == 1)

                   {

                            p2= DeleteNode(p2, head2);

                   }

                   else

                   {

                            p2= p2->next;

                            if(p2== p2->next)

                            {

                                     end++;

                            }

                   }

 

         }while(p2&&( p2 != head2 || (end <= 1 && p2 == head2)));

 

 

         printf("\n\n");

 

}

 

int main()

{

         intarr[] = {1, 2, 3};

         intan = sizeof(arr)/sizeof(arr[0]);

        

         Node* head1 = CreateList(arr, an);

         printf("链表A的元素: ");

         print(head1);

 

 

         intbrr[] = {1, -1, 2, 3};

         intbn = sizeof(brr)/sizeof(brr[0]);

 

         Node* head2 = CreateList(brr, bn);

         printf("链表B的元素: ");

         print(head2);

 

         DeleteCommonNode(head1,head2);

 

 

         printf("删除相同节点后再次遍历链表:\n");

         printf("删除公共节点后链表A的剩下元素:");

         print(head1);

         printf("删除公共节点后链表B的剩下元素:");

         print(head2);

 

         return0;

}

2.3 使用排序算法

2.3.1 思路

1)首先遍历链表A,把A中元素添加到数组A中,同理,把链表B的元素添加到数组B中。

2)对数组A,和数组B进行排序,再遍历一次已经有序的数组A和数组B,把相同元素填到数组C中,数组C中元素就是A和B中共同元素。

3)再次遍历链表A,遍历每一个元素Ai,使用二分查找其是否在数组C中,若在则删除之。

   同理对链表B也是执行相同过程;

4)结束

时间复杂度为O(mlgm+nlgn);

2.3.2 测试代码

#include <iostream>

#include <algorithm>

#include <bitset>

using namespace std;

 

#define NSIZ 100000

 

 

typedef struct Node_

{

         intdata;

         Node_* front, *next;

}Node;

 

bitset<NSIZ> bs; //bitset,一个bit表示一个数

int arr[NSIZ]; //存放链表A中元素

int brr[NSIZ]; //存放链表B中元素

int crr[NSIZ]; //存放链表A和B中公共元素

int cn = 0; //数组crr[]的长度

 

//打印链表

void print(Node * head)

{

         if(!head)

         {

                   printf("链表为空!!!\n");

                   return;

         }

 

         Node* p = head;

         do

         {

                   printf("%d", p->data);

                   p= p->next;

         }while(p!= head);

 

         printf("\n");

}

 

//创建链表

Node * CreateList(int arr[], int n)

{

         Node* head = 0, * p = 0;

         inti;

 

         if(head== 0)

         {

                   head= new Node();

                   head->data= arr[0];

                   head->front= head;

                   head->next= head;

                   p= head;

         }

 

         for(i= 1;i < n; ++i)

         {

                   Node* tmp = new Node();

                   tmp->data= arr[i];

        

                   tmp->next= p->next;

                   p->next= tmp;         

                  

                   tmp->front= p;        

                   p= tmp;

         }

         head->front= p;

         returnhead;

}

 

//若列表中剩下最后一个节点,删除后返回0

//若删除节点不是最后一个节点1)若非头结点,则直接返回该节点的下一个节点;2)若是头结点,调节头结点为下一个节点

Node* DeleteNode(Node * p, Node *&head)

{

 

         if(p->next== p) //链表中只有一个节点

         {

                   deletep;

                   p= 0;

                   head= p;

                   return0;

         }

 

         Node* p_next = p->next;

         p->front->next= p->next;

         p->next->front= p->front;

        

        

         if(p== head)

         {

                   head= p->next;

         }

 

         if(p)

         {

                   deletep;

                   p= 0;

         }

         returnp_next;

}

 

//遍历链表

int GetNode(Node * head, int arr[], int&len)

{

         if(head== 0)

         {

                   return0;

         }

         len= 0;

         Node* p = head;

        

         do

         {

                   arr[len++]= p->data;

                   p= p->next;

         }while(p!= head);

 

         returnlen;

}

 

//二分查找

int bin_search(int crr[], int cn, int key)

{

         intleft = 0, right = cn - 1, mid = 0;

        

         while(left<= right)

         {

                   mid= left + (right - left) / 2;

                   if(crr[mid]< key )

                   {

                            left= mid + 1;

                   }

                   elseif(crr[mid] > key)

                   {

                            right= mid - 1;

                   }

                   else

                   {

                            return1;

                   }

         }

 

         return0;

}

 

//首先遍历链表A和B获得数组A和数组B

//然后分别对数组A和B进行排序

//再次遍历有序数组A,B获得公共元素数组C

void Common(Node * head1, Node * head2)

{

 

         intan = 0, bn = 0;

         inti = 0, j = 0;

 

         GetNode(head1,arr, an);

         GetNode(head2,brr, bn);

 

        

         //使用库函数

         sort(arr,arr+an);

         sort(brr,brr+bn);

 

         //查找公共元素

         cn= 0;

         while(i< an && j < bn)

         {

                   if(arr[i]< brr[j])

                   {

                            ++i;

                   }

                   elseif(arr[i] > brr[j])

                   {

                            ++j;

                   }

                   else

                   {

                            crr[cn++]= arr[i++];

                            ++j;

                   }

         }

 

         //输出公共元素

         printf("输出公共元素:");

         for(i= 0;i < cn; ++i)

         {

                   printf("%d", crr[i]);

         }

         printf("\n");

 

}

 

 

先求出两个链表公用节点,然后利用二分查找在两个链表中分别删除之

void DeleteCommonNode(Node * &head1,Node * &head2)

{

         if(!head1|| !head2 )

         {

                   return;

         }

 

         //获得两个链表中的公共的节点

         Common(head1,head2);

        

         Node* p1 = head1, *p2 = head2;

         intend = 0;

 

         //删除链表A中公共节点

         do

         {

                   if(bin_search(crr,cn, p1->data) == 1)

                   {

                            p1= DeleteNode(p1, head1);

                   }

                   else

                   {

                            p1 = p1->next;

                            if(p1== head1)

                            {

                                     end++;

                            }

                   }

 

         }while(p1&&(p1 != head1 || (end <= 1 && p1 == head1)));

        

        

         //删除链表B中公共节点

         end= 0;

   do

         {

                   if(bin_search(crr,cn, p2->data) == 1)

                   {

                            p2= DeleteNode(p2, head2);

                   }

                   else

                   {

                            p2= p2->next;

                            if(p2== p2->next)

                            {

                                     end++;

                            }

                   }

 

         }while(p2&&( p2 != head2 || (end <= 1 && p2 == head2)));

 

         printf("\n");

 

}

 

int main()

{

         intarr[] = {1, 2, 3};

         intan = sizeof(arr)/sizeof(arr[0]);

        

         Node* head1 = CreateList(arr, an);

         printf("链表A的元素: ");

         print(head1);

 

 

         intbrr[] = {1, -1, 2, 3};

         intbn = sizeof(brr)/sizeof(brr[0]);

 

         Node* head2 = CreateList(brr, bn);

         printf("链表B的元素: ");

         print(head2);

 

         DeleteCommonNode(head1,head2);

 

 

         printf("删除相同节点后再次遍历链表:\n");

         printf("删除公共节点后链表A的剩下元素:");

         print(head1);

         printf("删除公共节点后链表B的剩下元素:");

         print(head2);

 

         return0;

}

至此,这个题目结束。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值