1. 程式人生 > >用單鏈表的方式實現集合的基本運算(資料結構C語言版)

用單鏈表的方式實現集合的基本運算(資料結構C語言版)

用單鏈表來實現結合的基本運算,首先用的是單鏈表所以我們就先給它建立一個頭結點並且為它分配空間,而結點的結構體中定義了兩個屬性 data域和next指標域。

實現集合元素的插入。我用的是單鏈表頭插法的方法,先建立一個新的結點用於輸入值然後插入到線性連結串列中去,然後依次挨個的在頭部插入,這裡需要注意的是線性連結串列的頭結點next指標域的指向“  p->next=L->next; L->next=p;”。

實現集合元素的輸出。定義一個具有結點結構的指標p來指向頭結點的next指標域,然後用一個while迴圈條件是“當p指標指向的結點的指標域為空時就停止迴圈”,用p指標來遍歷線性連結串列,然後列印輸出每個結點資料

p=p->nex”為了實現遍歷p指標每次要指向下一個結點,直至指向的內容為空就結束。當然在此過程進行中也要判斷該連結串列是否為空連結串列。

連結串列的清空。先判斷是否為空表,然後在進行清空,在清空時要實現斷鏈的操作然後將斷鏈出來的結點給釋放掉,鍛鍊操作“q=p;  p=q->next; ”將q結點斷出來。在最後一定要記得將L線性連結串列的next指標域置為 NULL 空,這樣才算是真正的清空。

實現兩個集合的並集並在該過程中除去重複的元素。首先要判斷Lc連結串列是否為空如果Lc連結串列不為空則就要進行連結串列清空,然後指標p控制掃描La的每一個結點(元素)指標q控制掃描連結串列

Lc的每一個結點(元素),如果La中沒找到與Lc連結串列中相同的結點時,就把La上結點在Lc上插入(把集合La的元素填入集合Lc)並採用頭插法的方式來進行。將Lb中的元素填入Lc中道理跟La操作相同

實現兩個集合的交集,並在該過程中除去重複的元素。跟並集一樣要先判斷Lc連結串列是否為空,然後讓p指標首先指向La的指標域,讓q指標首先指向Lb的指標域,讓s指標首先指向Lc的指標域

  while(q!=NULL)

        {

              if(q->data==p->data)   //如果找到了LaLb相同的元素就退出

                    break;

              else

                    q=q->next;   //如果沒有找到就繼續向下遍歷

        }

如果q=表示找到了LaLb共同的元素,此時再與Lc中的元素進行比較,if(s==NULL)   //s==NULL表示:s指標指向了空意味著沒找到與Lc裡面相同的重複元素然後就執行插入操作。

實現兩個集合的差集的操作與上面兩個操作類似只不過中間的一些運算條件與要變更一下,將if(q=NULL)變為if(q==NULL)就行了。

總的來說線性表它的特點就是它存在明顯的先後關係,可以用動態陣列或單鏈表的形式來方便實現,但需要注意的是連線先後關係的紐帶要找準來找到位置的方法從而確定先後關係然後進行一系列的運算。

程式碼如下:

#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR -1
typedef int ElemType;
typedef int Status;

typedef struct LNode{
	ElemType data;
	struct LNode *next;
} LNode,*LinkList;

//實現建立一個頭結點
Status InitList_L(LinkList &L)
{
	LinkList p;
	p=(LinkList)malloc(sizeof(LNode));
	if(!p)
		return ERROR;  //分配空間沒有成功 返回ERROR
	L=p;
	L->next=NULL;
	return OK;
}

//操作的功能選單
void menu()
{
	printf("************單鏈表(頭插法)集合運算************\n\n");
	printf("\t\t1.集合A資料輸入\n\n");
	printf("\t\t2.集合B資料輸入\n\n");
	printf("\t\t3.集合A資料顯示\n\n");
	printf("\t\t4.集合B資料顯示\n\n");
	printf("\t\t5.集合A和集合B的並集\n\n");
	printf("\t\t6.集合A和集合B的交集\n\n");
	printf("\t\t7.集合A和集合B的差集\n\n");
	printf("\t\t0.退出系統\n\n");
	printf("************單鏈表(頭插法)集合運算************\n");
	printf("請輸入選項:");
}

//實現集合元素的輸入
Status InputLinkList_L(LinkList &L,int n) //給集合輸入資料採用單鏈表頭插法
{
	LinkList p;
	int i=1;
	printf("單鏈表頭插法!\n");
	while(i<=n)
	{	
		printf("第%d個數據\n",i);
		p=(LinkList)malloc(sizeof(LNode));	//建立一個新的結點用於輸入值然後插入到線性連結串列中
		if(p)
		{
			scanf("%d",&(p->data));
			p->next=L->next;  //插入到頭部
			L->next=p;
		}
		else 
			return ERROR;
		i++;
	}
	return OK;
}

//實現集合元素的輸出
void OutputLinkList_L(LinkList L)  //輸出集合的資料
{
	LinkList p;  //定義一個指標p
	int i=0;
	p=L->next; //p指標指向頭結點的指標域
	while(p!=NULL)  //當p指標指向的結點的指標域為空時就停止迴圈
	{
		i++;
		printf("第%d個數據為:",i);
		printf("%d\n",p->data);  //用p指標來遍歷線性連結串列,然後列印輸出每個結點資料
		p=p->next;   //為了實現遍歷p指標每次要指向下一個結點,直至指向的內容為空就結束
	}
	if(i==0)
		printf("\n空連結串列,資料個數為 0.\n");
	else
		printf("連結串列的資料總數為:%d\n",i);
}

//實現連結串列的清空
Status ClearList_L(LinkList &L)
{
	LinkList p,q; //定義兩個指標p,q
	p=L->next;
	if(!p)        //如果p指向的連結串列L是一個空表 就直接返回OK(1)
		return OK;
	while(p)      //當p指向的連結串列L不是空表  則進行以下語句
	{
		q=p;      //表示指向頭結點下的第一個結點

		p=q->next; //實現對 q 結點 進行斷鏈

		free(q);   //釋放連結串列結點的空間
	}
	L->next=NULL; //將L連結串列的next指標域 置為 NULL 空
	return OK;
}

//實現兩個集合的並集 並在該過程中除去重複的元素
void Union(LinkList La,LinkList Lb,LinkList &Lc)
{
	LinkList p,q,s;
	if(Lc->next)
		ClearList_L(Lc); //如果Lc連結串列不為空則就要進行連結串列清空
	
	p=La->next;   //指標p控制掃描La的每一個結點(元素)
	while(p!=NULL)
	{
		q=Lc->next;  //指標q控制掃描連結串列Lc的每一個結點(元素)
		while(q && (q->data != p->data))
			q=q->next;
		if(!q) //La中沒找到與Lc連結串列中相同的結點時,就把La上結點在Lc上插入(把集合La的元素填入集合Lc)
		{
			s=(LinkList)malloc(sizeof(LNode));
			s->data=p->data;
			s->next=Lc->next;   //插入到頭部
			Lc->next=s;
		}
		p=p->next;  //指向下一個結點
	}
	
	p=Lb->next;
	while(p!=NULL)
	{
		q=Lc->next;
		while(q && (q->data != p->data))  //如果找到Lb中的元素與Lc中的元素相同則就繼續迴圈否則就結束迴圈
			q=q->next;
		if(!q) //滿足沒找到相同元素的情況
		{
			s=(LinkList)malloc(sizeof(LNode)); //建立一個新的結點
			s->data=p->data;    //將Lb中的元素賦給s結點
			s->next=Lc->next;  //然後插入到Lc表的頭部
			Lc->next=s;
		}
		p=p->next;
	}
}

//實現兩個集合的交集,並在該過程中除去重複的元素
void Intersection(LinkList La,LinkList Lb,LinkList &Lc)
{
	LinkList p,q,s,k;
	if(Lc->next)
		ClearList_L(Lc);
	p=La->next;  //讓p指標首先指向La的指標域
	while(p!=NULL)
	{
		q=Lb->next;
		while(q!=NULL)
		{
			if(q->data==p->data)   //如果找到了La與Lb相同的元素 就退出
				break;
			else
				q=q->next;
		}
		if(q!=NULL)  //q!=空  表示找到了La與Lb共同的元素
		{
			s=Lc->next;
			while(s!=NULL)
			{
				if(s->data==p->data) //如果在Lc中找到相同重複的元素 就break,開始下一個元素的對比
					break;
				else 
					s=s->next;
			}
			if(s==NULL)   //s==NULL表示:s指標指向了空 意味著沒找到與Lc裡面相同的重複元素 然後就執行插入操作
			{
				k=(LinkList)malloc(sizeof(LNode));
				k->data=p->data;
				k->next=Lc->next;
				Lc->next=k;
			}
		}
		p=p->next;  //指向下一個結點
	}
} 

//實現兩個集合的差集
void Difference(LinkList La,LinkList Lb,LinkList &Lc)
{
	LinkList p,q,s,k;
	if(Lc->next)
		ClearList_L(Lc);  //實現連結串列Lc的清空
	p=La->next;
	while(p!=NULL)
	{
		q=Lb->next;
		while(q!=NULL)
		{
			if(q->data==p->data)
				break;
			else
				q=q->next;
		}
		if(q==NULL)  //q == 空  表示La與Lb元素對比  在Lb中沒有發現有與La中相同的元素
		{
			s=Lc->next;
			while(s!=NULL)
			{
				if(s->data==p->data)
					break;
				else 
					s=s->next;
			}
			if(s==NULL)  //s == 空 表示在連結串列Lc中沒有找到重複的元素
			{
				k=(LinkList)malloc(sizeof(LNode));  //建立一個新的結點 用於賦值插入
				k->data=p->data;
				k->next=Lc->next;  //插入到Lc頭部
				Lc->next=k; 
			}
		}
		p=p->next;
	}
}

//主函式部分
void main()
{
	LinkList La,Lb,Lc;
	int choice;
	int num;
	InitList_L(La);
	InitList_L(Lb);
	InitList_L(Lc);
	while(1)
	{
		menu();
		scanf("%d",&choice);
		switch(choice)
		{
			case 1:
					printf("需要輸入幾個資料:");
					scanf("%d",&num);
					InputLinkList_L(La,num);
					getchar();getchar();system("cls"); //回車清屏操作
					break;
			case 2:
					printf("需要輸入幾個資料:");
					scanf("%d",&num);
					InputLinkList_L(Lb,num);
					getchar();getchar();system("cls");
					break;
			case 3:
					printf("集合A資料:\n");
					OutputLinkList_L(La);
					getchar();getchar();system("cls");
					break;
			case 4:
					printf("集合B資料:\n");
					OutputLinkList_L(Lb);
					getchar();getchar();system("cls");
					break;
			case 5:
					printf("集合A和集合B的並集為:\n");
					Union(La,Lb,Lc);
					OutputLinkList_L(Lc);
					getchar();getchar();system("cls");
					break;
			case 6:
					printf("集合A和集合B的交集為:\n");
					Intersection(La,Lb,Lc);
					OutputLinkList_L(Lc);
					getchar();getchar();system("cls");
					break;
			case 7:
					printf("集合A和集合B的差集為:\n");
					Difference(La,Lb,Lc);
					OutputLinkList_L(Lc);
					getchar();getchar();system("cls");
					break;
			case 0:
					printf("歡迎使用,下次再見!\n");
					exit(0);
			default:
					printf("輸入選項有誤!請輸入0~7\n");
					getchar();getchar();system("cls");
		}
	}
}