跳转至

顺序表集合运算与扩展操作

在顺序表核心操作的基础上,追加排序、查找、归并以及集合交并差等扩展功能。

原代码单独成篇时,核心操作(initlistlistinsertlistdeletedestroylist)与前一篇重复。通过跨页面依赖声明,本文只保留一份完整可运行的代码,避免两篇博文各自维护相同片段。

修正点:destroylist 补充内存释放;listdelete 参数改为引用;appendlistbyarray 修复了多余的偏移量计算;listappend 补充了失败时的返回值。

完整代码

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

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2

#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10

#define INTARRLEN(a) (sizeof(a)/sizeof(int))

typedef int elemtype;
typedef int status;

typedef struct
{
    elemtype * elem;
    int length;
    int listsize;
} sqlist;

// ===== 核心操作 =====

status initlist(sqlist &l)
{
    l.elem = (elemtype *)malloc(LIST_INIT_SIZE * sizeof(elemtype));
    if (!l.elem) exit(OVERFLOW);
    l.length = 0;
    l.listsize = LIST_INIT_SIZE;
    return OK;
}

status listinsert(sqlist &l, int i, elemtype e)
{
    if (i < 1 || i > l.length + 1) return ERROR;
    if (l.length >= l.listsize)
    {
        elemtype * newbase = (elemtype *)realloc(l.elem,
            (l.listsize + LISTINCREMENT) * sizeof(elemtype));
        if (!newbase) exit(OVERFLOW);
        l.elem = newbase;
        l.listsize += LISTINCREMENT;
    }
    elemtype * q = &(l.elem[i - 1]);
    for (elemtype * p = &(l.elem[l.length - 1]); p >= q; --p)
        *(p + 1) = *p;
    *q = e;
    ++l.length;
    return OK;
}

status listdelete(sqlist &l, int i, elemtype &e)         // 修正:参数改为引用
{
    if (i < 1 || i > l.length) return ERROR;
    elemtype * p = &(l.elem[i - 1]);
    e = *p;
    elemtype * q = l.elem + l.length - 1;
    for (++p; p <= q; ++p) *(p - 1) = *p;
    --l.length;
    return OK;
}

status destroylist(sqlist &l)
{
    free(l.elem);                                        // 修正:先释放内存再置零
    memset(&l, 0, sizeof(l));
    return OK;
}

// ===== 归并 =====

status listmerge(sqlist la, sqlist lb, sqlist &lc)
{
    elemtype * pa = la.elem;
    elemtype * pb = lb.elem;
    lc.listsize = lc.length = la.length + lb.length;
    elemtype * pc = lc.elem = (elemtype *)malloc(lc.listsize * sizeof(elemtype));
    if (!lc.elem) exit(OVERFLOW);
    elemtype * pa_last = la.elem + la.length - 1;
    elemtype * pb_last = lb.elem + lb.length - 1;
    while (pa <= pa_last && pb <= pb_last)
    {
        if (*pa <= *pb) *pc++ = *pa++;
        else *pc++ = *pb++;
    }
    while (pa <= pa_last) *pc++ = *pa++;
    while (pb <= pb_last) *pc++ = *pb++;
    return OK;
}

// ===== 排序与清空 =====

status listsort(sqlist &l)
{
    for (int i = 1; i < l.length; i++)
        for (int j = l.length - 1; j >= i; j--)
            if (l.elem[j] < l.elem[j - 1])
            {
                int iTemp = l.elem[j - 1];
                l.elem[j - 1] = l.elem[j];
                l.elem[j] = iTemp;
            }
    return OK;
}

status listclear(sqlist &l)
{
    if (!l.elem) exit(OVERFLOW);
    l.length = 0;
    return OK;
}

// ===== 追加与输出 =====

status listappend(sqlist &l, elemtype e)
{
    if (listinsert(l, l.length + 1, e) == OK)
        return OK;
    return ERROR;                                        // 修正:补充失败时的返回值
}

status printlist(sqlist &l)
{
    for (int i = 0; i < l.length; i++)
        printf("%d ", l.elem[i]);
    printf("\n");
    return OK;
}

status appendlistbyarray(sqlist &l, elemtype arr[], int len)
{
    for (int i = 0; i < len; i++)
        listappend(l, arr[i]);                           // 修正:去掉多余的 originlen 偏移
    return OK;
}

// ===== 查找 =====

int listcount(sqlist &l, elemtype e)
{
    int times = 0;
    for (int i = 0; i < l.length; i++)
        if (e == l.elem[i])
            times++;
    return times;
}

int listindex(sqlist &l, elemtype e)
{
    for (int i = 0; i < l.length; i++)
        if (e == l.elem[i])
            return i;
    return -1;
}

status locateelem(sqlist &l, elemtype e)
{
    for (int i = 0; i < l.length; i++)
        if (e == l.elem[i])
            return 1;
    return 0;
}

// ===== 集合运算 =====

status listintersect(sqlist &l1, sqlist &l2, sqlist &l3)
{
    for (int i = 0; i < l1.length; i++)
        for (int j = 0; j < l2.length; j++)
            if (l1.elem[i] == l2.elem[j])
                listappend(l3, l1.elem[i]);
    return OK;
}

status listunion(sqlist &l1, sqlist &l2, sqlist &l3)
{
    for (int i = 0; i < l1.length; i++)
        listappend(l3, l1.elem[i]);
    for (int i = 0; i < l2.length; i++)
        if (!locateelem(l1, l2.elem[i]))
            listappend(l3, l2.elem[i]);
    return OK;
}

status listdiffer(sqlist &l1, sqlist &l2, sqlist &l3)
{
    for (int i = 0; i < l1.length; i++)
        if (!locateelem(l2, l1.elem[i]))
            listappend(l3, l1.elem[i]);
    return OK;
}

// ===== 使用示例 =====

int main()
{
    sqlist l1, l2, l3;
    initlist(l1);
    initlist(l2);
    initlist(l3);

    int a1[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    int a2[] = {6, 7, 8, 9, 10, 11, 12, 13};
    appendlistbyarray(l1, a1, INTARRLEN(a1));
    appendlistbyarray(l2, a2, INTARRLEN(a2));

    printf("l1: "); printlist(l1);
    printf("l2: "); printlist(l2);

    printf("归并: ");
    listmerge(l1, l2, l3);
    printlist(l3);
    listclear(l3);

    printf("交集: ");
    listintersect(l1, l2, l3);
    printlist(l3);
    listclear(l3);

    printf("并集: ");
    listunion(l1, l2, l3);
    printlist(l3);
    listclear(l3);

    printf("差集 l1-l2: ");
    listdiffer(l1, l2, l3);
    printlist(l3);

    destroylist(l1);
    destroylist(l2);
    destroylist(l3);
    return 0;
}

操作说明

归并 listmerge 将两个已排序顺序表合并为一个有序表,前提是输入已有序。

排序 listsort 使用冒泡排序,每次内循环将较小值交换到数组前端。

集合运算 三函数均将结果追加至目标表 l3,调用前需先初始化 l3。并集和差集依赖 locateelem 判断元素是否已在另一表中。