数据结构专题实验1- 链表的应用(C语言实现)

一、实验概述

实验题目:求集合的并、交、差运算。
实验目的:掌握单链表的应用。
实验内容:编写一个程序,采用单链表表示集合,利用单链表操作,完成集合的并、交、差运算。
实验要求:

1.用C或C++实现运算。
2.Sort(slink *L)函数对链表中L所有数据节点按值域递增排序。
3.Union(slink *la,slink *lb, slink *lc)函数求两个集合的并集。
4.InerSect (slink *la,slink *lb, slink *lc)函数求集合的交集。
5.Subs(slink *la,slink *lb, slink *lc)函数求集合的差集。

二、代码结构

在这里插入图片描述

set.h

     声明链表结构体,以及与集合操作相关的函数。

在这里插入图片描述

function.cpp

	实现对集合操作相关的函数。包括集合的创建、判断、打印、删除等。

三、函数讲解

void InitializeList(slink *&plist);

	初始化链表的函数,创建表头。
void InitializeList(slink *&plist){
    plist = (slink*)malloc(sizeof(slink));
    if(plist == NULL){
       printf("fail to init list");
       exit(1);
    }
    plist->next = NULL;
}

bool ListisEmpty(slink *plist);

	检查链表(集合)是否为空的函数。因为会有空集的情况出现,所以要进行判断。
bool ListisEmpty(slink *plist){
    if(plist == NULL)
    return true;
    else
    return false;
}

void CreateSet(slink *&L);

	创建一个集合。通过键盘进行集合中元素的输入,当输入值为回车的时候停止。   
void CreateSet(slink *&L){
    slink *p;
    p = L ;//找到头节点
    int element;
    printf("please input several integer elements:");
    scanf("%d",&element);
    while(getchar()!='\n') {     
       p = p->next = (slink*)malloc(sizeof(slink));
       p->element = element;
       scanf("%d",&element);
    }
   p = p->next = (slink*)malloc(sizeof(Setnode));
   p->element = element;//再执行一次,不然会少最后一个元素
   p->next=NULL;
}

void PrintSet(slink *L);

	打印集合,利用while循环和链表的特性,进行遍历。
void PrintSet(slink *L){
   slink* p=L->next;
     while(p!=NULL){
        printf("%d ", p->element);
        p = p -> next;
     }
}

void Sort(slink *L);

    对链表L所有数据节点按值域递增排序。
    p1,p2,相当于指向同一集合的指针,在保证集合中元素不变的情况下对元素
的值进行比较。因为实验对于时间复杂度没有要求,我的方法就简单粗暴。相当
于是利用嵌套的while循环做了冒泡排序,注意重置p2指针的位置,保证下一次
循环从第一个元素开始比较。如果想缩短时间的话,可以在结构体中加一个int型
的变量,记录第一层while循环的次数,也就是p2重置的位置。同时在if执行的
块里添加一个记录变量,如果输入的集合本身有序,那么直接跳出循环。
void Sort(slink *L){
   slink *p1,*p2;
   p2 = p1 = L->next;
   int temp;
   //增值排序
   while(p1!=NULL){
      while(p2!=NULL){
         if(p1->element>p2->element){
               temp = p2->element;
               p2->element = p1->element;
               p1->element = temp;
           }          
         p2 = p2->next;
      }
      p1 = p1->next;
      p2 = p1;//重置p2指针位置
   }
}

void Union(slink *la,slink *lb,slink *lc);

	求两个有序集合的并集。
	la是指向集合A的指针,lb是指向集合B的指针,lc为所求集合(此处为并
集)指针。
void Union(slink *la,slink *lb,slink *lc){
   slink *pa,*pb,*pc;
   pc = lc,pa = la->next,pb = lb->next;
   
   //先把集合A、B中的元素全部赋给集合C,再利用去重函数删去重复元素
   while(pa!=NULL){
      pc = pc->next = (slink*)malloc(sizeof(Setnode));
      pc->element = pa->element;
      pa = pa->next;
   }

    while(pb!=NULL){
      pc = pc->next = (slink*)malloc(sizeof(Setnode));
      pc->element = pb->element;
      pb = pb->next;
   }
     Sort(lc);
     RemoveElement(lc);
     pc->next = NULL;
}

void InerSect(slink *la,slink *lb,slink *lc);

	求两个有序集合的交集。
	遍历并比较A、B两个中相同的元素,若相同,就加入C集合。
void InerSect(slink *la,slink *lb,slink *lc){
   slink *pa,*pb,*pc;
   pc = lc,pa = la->next,pb = lb->next;
    while(pa!=NULL){
      while(pb!=NULL){
         //寻找同时属于集合A、B的元素
         if(pa->element==pb->element){
            pc = pc->next = (slink*)malloc(sizeof(Setnode));
            pc->element = pa->element;
         }
         pb = pb->next;
      } 
      pa = pa->next;
      pb = lb->next;//重新定位
   }
     pc->next = NULL;
}

void Subs(slink *la,slink *lb,slink *le);

	求两个有序集合的差集。
	遍历并比较A、B两个集合中的元素,若相同,则替换,并继续向下遍历。
将符合条件的元素加入集合C。此处我选择将相同元素替换为-10000,在之后
遍历遇到这个元素便跳过。
void Subs(slink *la,slink *lb,slink *lc){
   slink *pa,*pb,*pc;
   pa = la->next, pb = lb->next, pc = lc;
   while(pa!=NULL){
        while(pb!=NULL){
         if(pa->element == pb->element){
             pa->element = -10000;
         }
        pb = pb->next;
      } 
      pa = pa->next;
      pb = lb->next;//重新定位
   }
      pa = la->next;
      while(pa!=NULL){
         if(pa->element==-10000){
            pa = pa->next;
          }
         else{
         pc = pc->next = (slink*)malloc(sizeof(Setnode));
         pc->element = pa->element;
         pa = pa->next;
        }
      }
      pc->next = NULL;
}

void RemoveElement(slink *L);

	删除重复元素。
	根据集合的定义,一个集合中不能存在相同的元素,因此在链表添加完元素
后要检查并去重。
    此处,寻找重复元素的思路和上述求差集的函数一致,如果有重复的,就
跳过,并改变链表连接的节点。
void RemoveElement(slink *L){
   slink *p,*p1,*p2;
   p = L->next;
      while(p!=NULL){
         p2 = p->next;
         while(p2!=NULL){
            if(p2->element == p->element){
               p2->element = -10000;//找到重复元素,替换为-10000;改进:可以新建一个链表来进行替换,这样就可以不改变原集合的元素
            }
            p2 = p2->next;
         }
         p = p->next;
      }

      p = L->next;
      p1 = L;
      while(p!=NULL){
         if(p->element==-10000){
            p = p->next;
          }
         else{
         p1 = p1->next = (slink*)malloc(sizeof(Setnode));
         p1->element = p->element;
         p = p->next;
        }
      }
      L = p1;//将去过重的集合赋给该链表
      L->next = NULL;//尾节点
}

四、结果演示

	空集的判断还没有加上,需要的朋友们可以自己动脑筋想一下。

在这里插入图片描述

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值