1. 程式人生 > >資料結構:求集合差集(c/c++)

資料結構:求集合差集(c/c++)

用帶頭結點的單鏈表表示整數集合,完成以下演算法並分析時間複雜度:

(1)設計一個演算法求兩個集合A和B的差集運算,即C=A-B,要求演算法的空間複雜度為O(1),並釋放單鏈表A和B中不需要的結點。

(2)假設集合中的元素按遞增排列,設計一個高效演算法求兩個集合A和B的差集運算,即C=A-B,要求演算法的空間複雜度為O(1),並釋放單鏈表A和B中不需要的結點。

#include<stdio.h>
#include<stdlib.h>

typedef struct LNode
{
	int data;
	struct LNode* next;
} LinkNode;

void DestroyList(LinkNode*L)  //銷燬線性表函式
{
	LinkNode*p=L->next,*q=L;
	while(p!=NULL)
	{
		free(q);
		q=p;
		p=p->next;
	}
	free(q);
}

void DispList(LinkNode*L)    //輸出函式
{
	LinkNode*p=L->next;
	while(p!=NULL)
	{
		printf("%d ",p->data);
		p=p->next;
	}
	printf("\n");
}

void CreatList(LinkNode*&L,int a[],int n)     //陣列資料建立連結串列函式尾插法
{
	LinkNode*p,*q;
	L=(LinkNode* )malloc(sizeof(LinkNode));
	q=L;
	for(int i=0;i<n;i++)
	{
		p=(LinkNode * )malloc(sizeof(LinkNode));
		p->data=a[i];
		q->next=p;
		q=p;
	}
	q->next=NULL;
}


void diff1(LinkNode*&A,LinkNode*&B)      //第一小題函式
{
	LinkNode*a,*b,*a_prior,*b_prior;     //a_prior,b_prior分別為遍歷迴圈中a,b節點的前驅節點
	a_prior=A;
	int T;                               //輔助變數T
	for(a=A->next;a!=NULL;a=a->next)     //遍歷A中元素
	{
		b_prior=B;
		T=1;
		for(b=B->next;b!=NULL;b=b->next) //對A中,每一個元素都遍歷一遍B表
		{
			if(a->data==b->data)         //若兩表中出現相同元素,則刪除A,B中此元素所在節點(刪除B中節點為減少以後遍歷B表次數)
			{
				T=0;
				a_prior->next=a->next;   //跳過a元素將a前後元素連結
				free(a);
				a=a_prior;               //∵這裡if後break跳過B迴圈後A迴圈會執行a節點前移,既下一刻開始判斷被刪除節點的下一節點
				b_prior->next=b->next;   //跳過b元素將b前後元素連結
				free(b);
				b=b_prior->next;
				break;
			}
			b_prior=b_prior->next;         
		}
		if(T) //若T==0說明原a節點已刪除,此刻a節點位置為a_prior位置,下一刻a節點前移,∴a_prior作為a節點的前驅節點此時就不必前移了
    		a_prior=a_prior->next;
	} 
}


void diff2(LinkNode*&A,LinkNode*&B)   //第二小題函式
{
	LinkNode*a=A->next,*b=B->next,*a_prior=A;  //a_prior為a節點的前驅節點
	while(a!=NULL && b!=NULL) 
	{
		if(a->data > b->data)         //若a節點的值大於b節點,則b節點後移
			b=b->next;
		else if(a->data < b->data)    //若a節點的值小於b節點,則a節點後移
		{
			a_prior=a;                //先將a的前驅節點前移,再將a節點前移
			a=a->next;
		}
		else                          //若兩值相等,則刪a節點
		{                             //b不必刪除 ∵到後面有銷燬函式銷燬b,這裡刪除b並不能像第一題一樣減少遍歷次數
			a_prior->next=a->next;    //跳過a元素將a前後元素連結
			free(a);
			a=a_prior->next;
		}
	}
}

void main()
{
	int A[7]={9,5,6,7,1,8,2},B[4]={8,-1,5,3};          //無序陣列,集合運算A-B應該為9,6,7,1,2 (以檢測結果)
	int a[10]={0,1,2,3,4,5,6,7,8,9},b[5]={2,4,6,8,10}; //有序陣列,集合運算a-b應該為0,1,3,5,7,9
	LinkNode*LA=NULL,*LB=NULL;
	CreatList(LA,A,7);          //建立無序連結串列LA,LB
	CreatList(LB,B,4);
	diff1(LA,LB);               //第一題函式
	DestroyList(LB);            //根據題目要求釋放A和B中不需要的節點,則B連結串列全刪
	DispList(LA);               //最後(1)題答案即為diff1後的連結串列A,將答案輸出
	DestroyList(LA);            //第一題已完成,刪除原表LA,重置A,B表並開始(2)題
	CreatList(LA,a,10);         //建立有序表A,B
	CreatList(LB,b,5); 
	diff2(LA,LB); 
	DestroyList(LB);
	DispList(LA);
	DestroyList(LA);
}