哈工大数据结构与算法 作业1——线性结构的存储结构与应用(SeqList)

该文章详细介绍了线性表的三种基本存储结构——顺序表、单链表和静态链表,并提供了C语言实现,包括初始化、插入、删除、查找、逆置、删除重复元素、循环移动和合并排序线性表等算法。同时,作者反思了代码设计中的不足,如变量命名、输入提示和注释规范等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作业题目:线性表的基本存储结构的实现与应用

顺序表与单链表是线性表的两种最基本的存储结构,而静态链表是两者的 完美结合,是系统进行动态存储分配的方法基础。线性表的这三种存储结构不但是其他数据结构(如树形结构、图型结构、集合等)存储方法的重要基础,同时本身也有广泛的应用。

作业要求

1. 实现线性表的顺序存储结构(SeqList)和链式存储结构(LinkList)。
2. 在上述存储结构的基础上,分别实现以下算法:
① 删除给定元素的算法。
② 对于已排好序的线性表,删除所有重复元素的算法。
③ 线性表“逆置”算法。
④ 线性表循环左移/右移 k 位的算法。
⑤ 合并两个已排好序的线性表的算法。
3. 选做:(可以不做,供学有余力、有兴趣的同学探索)
① 你能实现线性表的静态链表存储结构吗?
② 你能在静态链表上实现线性表的“逆置”算法吗?

存储结构

#define maxlength 100
#define ElemType int
typedef struct
{
    ElemType elem[maxlength];//下标为0的单元不存放线性表中元素
    int last;//最后一个元素在数组中位置
}SeqList;

部分基本操作

初始化线性表 

读取初始化时元素的个数,依次将各个元素加入到线性表中,当输入元素个数大于等于maxlength时提示"Too many elements !!"。

void Assign_Initial_Value(SeqList *L)
{
    int num=maxlength+1,i;
    printf("Please input the number of elements:");
    while(num>=maxlength)//元素个数最多为maxlength-1
    {
        scanf("%d",&num);
        if(num>=maxlength)
        {
            printf("Too many elements !!\n");
        }
    }
    printf("Input them:");
    for(i=1;i<=num;i++)
    {
        scanf(" %d",&L->elem[i]);
    }
    L->last=num;
    printf("success !!\n");
}

End(L)  返回最后一个元素的后一位置

给int定义别名position便于区分是否用于表示元素位置。

typedef int position
position End(SeqList L)
{
    return (L.last+1);
}

插入(在p位置插入元素x)

课本(数据结构与算法(第五版)高等教育出版社 张岩等主编)中代码使用C++语法,用'&'进行引用传递。如果使用C语言,可以考虑把'&'使用'*'替换,函数调用时,用'&'传址。

插入新元素,对插入元素位置及其后面元素依次后移即可。

不要忘记对L->last进行加1操作。

void Insert (ElemType x ,position p ,SeqList *L)
{
    position q;
    if(L->last>=maxlength-1)//x插入前表已满
    {
        printf("List is full !!");
    }
    else if((p>L->last+1)||p<1)//x插入位置错误
    {
        printf("position does not exist !!");
    }
    else
    {
        for(q=L->last;q>=p;q--)
        {
            L->elem[q+1]=L->elem[q];//位置p后元素逐个后移
        }
        L->elem[p]=x;
        L->last++;//勿忘
    }
}

删除给定位置的元素

勿忘对L->last进行减1操作

void Delete(position p,SeqList *L)
{
    position q;
    if((p>L->last)||(p<1))
    {
        printf("position does not exist !!");
    }
    else
    {
        for(q=p;q<=(L->last);q++)
        {
            L->elem[q]=L->elem[q+1];
        }
        L->last--;
    }
}

打印线性表

void Print(SeqList*L)
{
    int i;
    for(i=1;i<=L->last;i++)
    {
        printf("%d  ",L->elem[i]);
    }
    printf("\n");
}

查找某个元素(查找某个元素第一次出现的位置)

position Locate(ElemType x,SeqList *L)
{
    printf("Input the element you want to find:");
    scanf(" %d",&x);
    position q;
    for(q=1;q<=(L->last);q++)
    {
        if(L->elem[q]==x)
            return q;
    }
    return (L->last+1);//找不到则返回最后元素后一位置
}

作业中算法

1.删除给定元素的算法

该函数中调用了基本操作中的删除某一位置元素函数

void Delete_Element(ElemType x,SeqList *L)
{
    int i=1;
    while(i<=L->last)
    {
        if(L->elem[i]==x)
        {
            Delete(i,L);
        }
        else
            i++;
    }
}

2.删除重复元素算法(对于排好序的数组)

对于排好序的数组,重复元素必定相邻,只需要对相邻元素进行依次判断即可。

void Delete_Duplicate_Orderly(SeqList *L)
{
    int i=1;
    while(i<=L->last)
    {
        if(L->elem[i]==L->elem[i+1])
        {
            Delete(i+1,L);
        }
        else
        {
            i++;
        }
    }
}

3.逆置算法

依次交换第一和最后一个元素,第二和倒数第二个元素...

void Inverse(SeqList *L)
{
    int temp,i;
    for(i=1;i<=(L->last)/2;i++)
    {
        temp=L->elem[i];
        L->elem[i]=L->elem[End(*L)-i];
        L->elem[End(*L)-i]=temp;
    }
}

4.循环移动算法

如图,将如下线性表循环左移2(unit)个单位,申请一块临时空间用于存储前2(unit)个元素,再将后面元素依次前移两(unit)个单位,最后再将临时空间中元素放到后面。
循环左移同理。

void Cyclic_Movement(SeqList *L)
{
    int judge;
    int i,k=0;
    int unit=L->last+1;
    printf("left or right?(1 for left and 2 for right)\n");
    scanf(" %d",&judge);
    if(judge!=1&&judge!=2)
    {
        printf("Please input a proper number!");
        scanf(" %d",&judge);
    }
    int *s,*q;
    while(unit>L->last)
    {
        printf("How many units to move?");
        scanf(" %d",&unit);
    }
    s=(ElemType *)malloc(unit*sizeof(ElemType));//申请临时s存放左移前的元素
    q=s;
    if(judge==1)//循环左移
    {
        for(i=1;i<=unit;i++)
        {
            s[i-1]=L->elem[i];
        }
        //printf("s[0] is %d",s[0]);
        for(i=unit+1;i<=L->last;i++)
        {
            L->elem[i-unit]=L->elem[i];
        }
        for(i=End(*L)-unit;i<End(*L);i++)
        {
            L->elem[i]=s[k];
            k++;
        }
    }
    else if(judge==2)//循环右移
    {
        for(i=L->last;i>=End(*L)-unit;i--)
        {
            s[k]=L->elem[i];
            k++;
        }
        for(i=L->last-unit;i>=1;i--)
        {
            L->elem[i+unit]=L->elem[i];
        }
        k=0;
        for(i=1;i<=unit;i++)
        {
            L->elem[i]=s[k];
            k++;
        }
    }
    free(q);
}

5.合并线性表算法

合并两个有序表需要依次比较两个表中元素大小,将较小元素放入到Lc中。然后再对La中元素已经全部放入和Lb中元素已经全部放入分别进行考虑。

void Merge(SeqList *La,SeqList *Lb,SeqList *Lc)
{
    int i=0;
    position a=1;//标记数组a移动情况
    position b=1;//标记数组b移动情况
    Lc->last=La->last+Lb->last;
    while(a<=La->last||b<=Lb->last)
    {
        i++;
        if(La->elem[a]<=Lb->elem[b])
        {
            Lc->elem[i]=La->elem[a];
            a++;
        }
        else
        {
            Lc->elem[i]=Lb->elem[b];
            b++;
        }
    }
    if(a==La->last)//La中全部元素已经进入数组
    {
        while(b<=Lb->last)
        {
            i++;
            Lc->elem[i+1]=Lb->elem[b];
            b++;
        }
    }
    else//Lb中全部元素已经进入数组
    {
         while(a<=La->last)
        {
            i++;
            Lc->elem[i+1]=La->elem[a];
            a++;
        }
    }
    for(i=1;i<=Lc->last;i++)
    {
        printf("%d  ",Lc->elem[i]);
    }
}

测试结果

Code::Blocks下测试结果:

 未将Merge函数写入menu中,单独测试。

不足与反思

1.在函数设计前未规划Menu函数,导致各个函数的形参数量设计十分混乱(在作业中未明确要设计一个菜单界面,主要侧重算法设计,可以不设计menu)。
2.输入提示信息中英文混杂,未提前规划。
3.部分变量名的命名未能体现其具体作用。
4.输入提示信息时而放入算法函数中,时而放入menu函数中,十分混乱。
5.因为怕麻烦未将合并线性表操作加入到menu中。
6.L->last和End(L)函数得到的值相差1,编程过程中将两者混用,最好将两者统一。
7.注释不规范,不能清晰地反映代码用途。
8.部分for循环换成while循环会更加简洁,尤其是在某些对错误输入进行处理的地方。
9.合并算法仅考虑了升序排列,未考虑降序的情况。
PS:小白一枚,C语言基础薄弱,以此博客记录自己学习过程,分享自己的心得,恳请批评指正。

完整代码

#include <stdio.h>
#include <stdlib.h>
#define maxlength 100
#define ElemType int
/*存储结构*/
typedef struct
{
    ElemType elem[maxlength];//下标为0的单元不存放线性表中元素
    int last;//最后一个元素在数组中位置

}SeqList;

/*打印线性表中所有元素*/
void Print(SeqList*L)
{
    int i;
    for(i=1;i<=L->last;i++)
    {
        printf("%d  ",L->elem[i]);
    }
    printf("\n");
}

typedef int position;//便于区分哪些变量表示元素位置

/*函数End()L返回表中最后一个元素的后一位置*/
position End(SeqList L)
{
    return (L.last+1);
}

/*把x插入表中位置p处*/
void Insert (ElemType x ,position p ,SeqList *L)
{
    position q;
    if(L->last>=maxlength-1)//x插入前表已满
    {
        printf("List is full !!");
    }
    else if((p>L->last+1)||p<1)//x插入位置错误
    {
        printf("position does not exist !!");
    }
    else
    {
        for(q=L->last;q>=p;q--)
        {
            L->elem[q+1]=L->elem[q];//位置p后元素逐个后移
        }
        L->elem[p]=x;
        L->last++;//勿忘
    }
}

/*删除L中位置p的元素*/
void Delete(position p,SeqList *L)
{
    position q;
    if((p>L->last)||(p<1))//删除元素位置不存在
    {
        printf("position does not exist !!");
    }
    else
    {
        for(q=p;q<=(L->last);q++)
        {
            L->elem[q]=L->elem[q+1];
        }
        L->last--;
    }
}

/*删除给定元素*/
void Delete_Element(ElemType x,SeqList *L)
{
    int i=1;
    while(i<=L->last)
    {
        if(L->elem[i]==x)
        {
            Delete(i,L);
        }
        else
            i++;
    }
}

/*返回表L中元素x的位置*/
position Locate(ElemType x,SeqList *L)
{
    printf("Input the element you want to find:");
    scanf(" %d",&x);
    position q;
    for(q=1;q<=(L->last);q++)
    {
        if(L->elem[q]==x)
            return q;
    }
    return (L->last+1);//找不到则返回最后元素后一位置
}

/*对已排好序的线性表删除所有重复元素*/
void Delete_Duplicate_Orderly(SeqList *L)
{
    int i=1;
    while(i<L->last)
    {
        if(L->elem[i]==L->elem[i+1])
        {
            Delete(i+1,L);
        }
        else
        {
            i++;
        }
    }
}

/*初始化线性表*/
void Assign_Initial_Value(SeqList *L)
{
    int num=maxlength+1,i;
    printf("Please input the number of elements:");
    while(num>=maxlength)//元素个数最多为maxlength-1
    {
        scanf("%d",&num);
        if(num>=maxlength)
        {
            printf("Too many elements !!\n");
        }
    }
    printf("Input them:");
    for(i=1;i<=num;i++)
    {
        scanf(" %d",&L->elem[i]);
    }
    L->last=num;
    printf("success !!\n");
}

/*逆置线性表*/
void Inverse(SeqList *L)
{
    int temp,i;//temp用于暂时存放交换元素
    for(i=1;i<=(L->last)/2;i++)
    {
        temp=L->elem[i];
        L->elem[i]=L->elem[End(*L)-i];
        L->elem[End(*L)-i]=temp;
    }
}

/*循环移动*/
void Cyclic_Movement(SeqList *L)
{
    int judge;
    int i,k=0;
    int unit=L->last+1;
    printf("left or right?(1 for left and 2 for right)\n");
    scanf(" %d",&judge);
    while(judge!=1&&judge!=2)
    {
        printf("Please input a proper number!");
        scanf(" %d",&judge);
    }
    int *s,*q;
    while(unit>L->last)
    {
        printf("How many units to move?");
        scanf(" %d",&unit);
    }
    s=(ElemType *)malloc(unit*sizeof(ElemType));//申请临时s存放左移前的元素
    q=s;
    if(judge==1)//循环左移
    {
        for(i=1;i<=unit;i++)
        {
            s[i-1]=L->elem[i];
        }
        for(i=unit+1;i<=L->last;i++)
        {
            L->elem[i-unit]=L->elem[i];
        }
        for(i=End(*L)-unit;i<End(*L);i++)
        {
            L->elem[i]=s[k];
            k++;
        }
    }
    else//循环右移
    {
        for(i=L->last;i>=End(*L)-unit;i--)
        {
            s[k]=L->elem[i];
            k++;
        }
        for(i=L->last-unit;i>=1;i--)
        {
            L->elem[i+unit]=L->elem[i];
        }
        k=0;
        for(i=1;i<=unit;i++)
        {
            L->elem[i]=s[k];
            k++;
        }
    }
    free(q);
}

/*逆置线性表*/
void Merge(SeqList *La,SeqList *Lb,SeqList *Lc)
{

    int i=0;
    position a=1;//标记数组a移动情况
    position b=1;//标记数组b移动情况
    Lc->last=La->last+Lb->last;
    while(a<=La->last||b<=Lb->last)
    {
        i++;
        if(La->elem[a]<=Lb->elem[b])
        {
            Lc->elem[i]=La->elem[a];
            a++;
        }
        else
        {
            Lc->elem[i]=Lb->elem[b];
            b++;
        }
    }
    if(a==La->last)//La中全部元素已经进入数组
    {
        while(b<=Lb->last)
        {
            i++;
            Lc->elem[i+1]=Lb->elem[b];
            b++;
        }
    }
    else//Lb中全部元素已经进入数组
    {
         while(a<=La->last)
        {
            i++;
            Lc->elem[i+1]=La->elem[a];
            a++;
        }
    }
    for(i=1;i<=Lc->last;i++)
    {
        printf("%d  ",Lc->elem[i]);
    }
}

/*菜单*/
void Menu(SeqList*L)
{
    printf("************************菜单************************\n");
    printf("*1.初始化一个数组************2.删除某个位置的元素***\n");
    printf("*3.删除给定元素**************4.删除所有重复元素*****\n");
    printf("*5.逆置线性表****************6.循环左移/右移k个单位*\n");
    printf("*7.查找元素位置**************8.插入某一元素*********\n");
    printf("*9.打印线性表***************10.退出*****************\n");
    int i=0;
    int choose=0;
    int x=0;
    position p=0;
    for(i=0;;i++)
    {
        printf("你想要的操作是?");
        scanf(" %d",&choose);
        switch(choose)
        {
            case 1:Assign_Initial_Value(L);break;
            case 2:printf("Input the position you want to delete:");
                    scanf(" %d",&p);
                    Delete(p,L);
                    Print(L);
                    break;
            case 3:printf("Input the element you want to delete:");
                    scanf(" %d",&x);
                    Delete_Element(x,L);
                    Print(L);
                    break;
            case 4:Delete_Duplicate_Orderly(L);
                    Print(L);
                    break;
            case 5:Inverse(L);
                    Print(L);
                    break;
            case 6:Cyclic_Movement(L);
                    Print(L);
                    break;
            case 7:printf("Input the element you want to search\n");
                    scanf(" %d",&x);
                    printf("poisition is %d",Locate(x,L));
                    break;
            case 8:printf("where to insert the element?\n");
                    scanf(" %d",&p);
                    printf("the element is ? \n");
                    scanf(" %d",&x);
                    Insert(x,p,L);
                    Print(L);
                    break;
            case 9:Print(L);
            case 10:exit(0);
            default:printf("Wrong!!Please input a proper number!!\n");
        }
    }
}

int main()
{
    SeqList L;
    Menu(&L);
    /*测试Merge算法代码*/
    /*SeqList La;
    Assign_Initial_Value(&La);
    SeqList Lb;
    Assign_Initial_Value(&Lb);
    SeqList Lc;
    Merge(&La,&Lb,&Lc);*/
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值