求集合(用单链表表示)的并、交和差运算

#include <stdio.h>
#include <malloc.h>

typedef char ElemType;
typedef struct LNode {
    ElemType data; //数据域
    struct LNode *next; //指向后继结点
}LinkNode; // 声明单链表结点类型

/*------------------------尾插法建立单链表---------------------------*/
static void create_list_rear(LinkNode *&L, ElemType a[], int n) // 指针的引用
{
    LinkNode *s, *r;
    int i;

    L = (LinkNode *)malloc(sizeof(LinkNode)); // 创建头结点
    L->next = NULL;
    r = L; // r始终指向尾结点,开始时指向头结点
    for(i = 0; i < n; i++)
    {
        // 创建新结点s
        s = (LinkNode *)malloc(sizeof(LinkNode));
        s->data = a[i];
        r->next = s; // 将结点s插入r结点之后
        r = s;
    }
    // 尾结点next域置为NULL
    r->next = NULL;
}

/*------------------------输出线性表---------------------------*/
static void display_list(LinkNode *L)
{
    LinkNode *p = L->next;

    while(p != NULL)
    {
        printf("%c ", p->data);// p不为NULL,输出p结点的数据域
        p = p->next; // p移向下一个结点
    }

    printf("\n");
}

/*------------------------销毁线性表---------------------------*/
static void destroy_list(LinkNode *&L)
{
    LinkNode *pre = L, *p = pre->next;

    while(p != NULL)
    {
        free(pre);
        pre = p;
        p = pre->next; // pre、p同步后移一个结点
    }
    free(pre); // 此时p为NULL,pre指向尾结点,释放它
}

/*------------------------单链表元素递增排序---------------------------*/
static void sort_list(LinkNode *&L) // 指针的引用
{
    LinkNode *p;
    LinkNode *pre;
    LinkNode *q;

    // p指向L的第2个数据结点
    p = L->next->next;
    // 构造只含有一个数据结点的有序表
    L->next->next = NULL;
    while(p != NULL)
    {
        // q保存p结点的后继结点
        q = p->next;
        // 从有序表开头进行比较,pre指向插入结点p的前驱结点
        pre = L;
        while(pre->next != NULL && pre->next->data < p->data)
            pre = pre->next; //在有序表中查找pre结点
        // 在结点pre之后插入p结点
        p->next = pre->next;
        pre->next = p;
        // 扫描原单链表余下的结点
        p = q;
    }
}

/*------------------------求两个有序集合的并---------------------------*/
// 算法设计采用二路归并+尾插法建表思路
static void union_list(LinkNode *ha, LinkNode *hb, LinkNode *&hc)// 指针的引用
{
    LinkNode *pa = ha->next;
    LinkNode *pb = hb->next;
    LinkNode *s, *tc;

    // 创建头结点hc
    hc = (LinkNode *)malloc(sizeof(LinkNode)); // 分配内存空间
    tc = hc; // tc指向新创建的头结点hc
    while(pa != NULL && pb != NULL)
    {
        if(pa->data < pb->data)
        {
            // 复制结点
            s = (LinkNode *)malloc(sizeof(LinkNode));
            s->data = pa->data;
            // 将s结点插入到头结点tc之后
            tc->next = s;
            tc = s;
            // pa后移一个结点
            pa = pa->next;
        }
        else if(pa->data > pb->data)
        {
            // 复制结点
            s = (LinkNode *)malloc(sizeof(LinkNode));
            s->data = pb->data;
            // 将s结点插入到头结点tc之后
            tc->next = s;
            tc = s;
            // pb后移一个结点
            pb = pb->next;
        }
        else
        {
            // 复制结点
            s = (LinkNode *)malloc(sizeof(LinkNode));
            s->data = pa->data;
            // 将s结点插入到头结点之后
            tc->next = s;
            tc = s;
            // 重复的元素只复制一个结点
            pa = pa->next;
            pb = pb->next;
        }
    }
    // 复制余下的结点
    if(pb != NULL)
        pa = pb;
    while(pa != NULL)
    {
        // 复制结点
        s = (LinkNode *)malloc(sizeof(LinkNode));
        s->data = pa->data;
        // 将s结点插入到tc之后
        tc->next = s;
        tc = s;
        // pa后移一个结点
        pa = pa->next;
    }
    tc->next = NULL;
}

/*------------------------求两个有序集合的交---------------------------*/
// 算法设计采用二路归并+尾插法建表思路
static void inter_sect(LinkNode *ha, LinkNode *hb, LinkNode *&hc)// 指针的引用
{
    LinkNode *pa = ha->next; // pa指向第一个集合中的第一个数据结点
    LinkNode *pb;
    LinkNode *s;
    LinkNode *tc;

    // 创建头结点hc
    hc = (LinkNode *)malloc(sizeof(LinkNode)); // 分配内存空间
    tc = hc; // tc指向新创建的头结点hc
    while(pa != NULL)
    {
        pb = hb->next;
        while(pb != NULL && pb->data < pa->data)
            pb = pb->next;
        // 若pa结点值在B中
        if(pb != NULL && pb->data == pa->data)
        {
            // 复制结点
            s = (LinkNode *)malloc(sizeof(LinkNode));
            s->data = pa->data;
            // 将s结点插入到tc之后
            tc->next = s;
            tc = s;
        }
        pa = pa->next;
    }
    tc->next = NULL;
}

/*------------------------求两个有序集合的差---------------------------*/
// 算法设计采用二路归并+尾插法建表思路,C = A - B, C中含有所有属于集合A而不属于集合B的元素
static void subs(LinkNode *ha, LinkNode *hb, LinkNode *&hc)
{
    LinkNode *pa = ha->next;
    LinkNode *pb;
    LinkNode *s;
    LinkNode *tc;

    // 创建头结点hc
    hc = (LinkNode *)malloc(sizeof(LinkNode)); // 分配内存空间
    tc = hc; // tc指向新创建的头结点hc
    while(pa != NULL)
    {
        pb = hb->next;
        while(pb != NULL && pb->data < pa->data)
        {
            pb = pb->next;
        }
        // 若pa结点值不在B中
        if(!(pb != NULL && pb->data == pa->data))
        {
            // 复制结点
            s = (LinkNode *)malloc(sizeof(LinkNode));
            s->data = pa->data;
            // 将s结点插入到tc结点之后
            tc->next = s;
            tc = s;
        }
        pa = pa->next;
    }
    tc->next = NULL;
}

int main(int argc, char **argv)
{
    LinkNode *ha;
    LinkNode *hb;
    LinkNode *hc;
    int n;

    ElemType a[] = {'c', 'a', 'e', 'h'};
    ElemType b[] = {'f', 'h', 'b', 'g', 'd', 'a'};
    printf("集合的运算如下:\n");
    n = 4;
    create_list_rear(ha, a, n);
    n = 6;
    create_list_rear(hb, b, n);
    printf("原集合A:");
    display_list(ha);
    printf("原集合B:");
    display_list(hb);

    sort_list(ha);
    sort_list(hb);
    printf("有序集合A:");
    display_list(ha);
    printf("有序集合B:");
    display_list(hb);

    union_list(ha, hb, hc);
    printf("集合的并C:");
    display_list(hc);

    inter_sect(ha, hb, hc);
    printf("集合的交C:");
    display_list(hc);

#if 1
    subs(ha, hb, hc);
    printf("集合的差C:");
    display_list(hc);
#endif

    destroy_list(ha);
    destroy_list(hb);
    destroy_list(hc);

    return 0;
}
测试结果:

集合的运算如下:
原集合A:c a e h
原集合B:f h b g d a
有序集合A:a c e h
有序集合B:a b d f g h
集合的并C:a b c d e f g h
集合的交C:a h
集合的差C:c e

猜你喜欢

转载自blog.csdn.net/xiezhi123456/article/details/86438837
今日推荐