前言

本次实验为个人作业,这里只作为记录和参考,代码部分注释自己看,部分代码无用注释并未删除,是写代码时测试用的,请自行删除,代码内所需文件请自行建立

一、实验目的

1、帮助读者复习C语言程序设计中的知识。
2、熟悉线性表的逻辑结构。
3、熟悉线性表的基本运算在两种存储结构上的实现。
4、掌握顺序表的存储结构形式及其描述和基本运算的实现。
5、熟练掌握动态链表结构及有关算法的设计

二、实验环境

  1. PC机一台,Dev-c或CodeBlocks

三、实验内容

题目一:线性表的基本操作(要求必须采用顺序存储结构)

[问题描述]
实现线性表的建立、求长度,取元素、修改元素、插入、删除等基本操作。要求采用顺序存储结构完成。
[基本要求]
(1)依次从键盘或文件读入数据,建立线性表A和表B;
(2)输出两个线性表中的数据元素;
(3)求线性表A和表B的长度;
(4)取表A的第3个元素和修改表B的第6个元素15为14;
(5)实现在表A的第3个位置前插入元素6,删除原来第3个位置(插入操作后第4个为位置)元素8;
(6)将两个有序的线性表表A和表B合并成一个有序线性表(元素可以重复),测试数据经过上述修改后输出结果为2 3 5 6 6 8 9 11 11 14 20;
[测试数据]
ListA.txt文件内容如下:3 5 8 11
ListB.txt文件内容如下:2 6 8 9 11 15 20

题目二:图书管理系统的单链表存储(要求必须采用链式存储)

[问题描述]
从book.txt中读入图书数据,已结构体Book作为一行图书记录的数据存储结构,实现带头结点的图书信息单链表的建立、求长度,取元素、修改元素、插入、删除等单链表的基本操作。(程序参考I/O框架已给出)
[基本要求]
(1)依次book.txt文件读入数据,建立带头结点的单链表;
(2)输出单链表中的数据元素
(3)求单链表的长度;
(4)根据指定条件能够取出元素和修改元素;(取出和修改位置内容任选)
(5)实现在指定位置插入和删除元素的功能。(插入和删除位置和内容任选)
[测试数据] book.txt

ISBN    书名    定价
9787302257646    程序设计基础    25
9787302219972     单片机技术及应用    32
9787302203513     编译原理    46
9787811234923     汇编语言程序设计教程    21
9787512100831     计算机操作系统    17
9787302265436     计算机导论实验指导    18
9787302180630    实用数据结构    29
9787302225065     数据结构(C语言版)    38
9787302171676     C#面向对象程序设计    39
9787302250692     C语言程序设计        42
9787302150664     数据库原理    35
9787302260806     Java编程与实践    56
9787302252887     Java程序设计与应用教程    39
9787302198505     嵌入式操作系统及编程    25
9787302169666     软件测试    24
9787811231557     Eclipse基础与应用    35

四、实验记录与分析


此部分内容要求有效果截图和实现过程的文字描述,代码要求结合截图和文字,粘贴核心部分内容,并加入必要注释!


五、实验总结


实验总结请从下面课程目标3的能力要求出发,客观描述自己通过理论和实践内容的学习和练习,能力方面的变化情况。


题目一实现线性表顺序存储操作代码

#include<iostream>
#include<fstream>

#define MAXSIZE 100
#define ERROR 0
#define OK 1
using namespace std;

//定义顺序表(表结构)
typedef int ElemType;//初始化一个通配的类型,防止数据换类型
typedef struct {
    ElemType *elem;//地址
    int length;
} SqList;

//初始化顺序表,创建
void InitSqList(SqList &L) {
    L.elem =new int[MAXSIZE];//为顺序表分配MAXSIZE大小的空间
    if(!L.elem) exit(ERROR);//存储分配失败退出
    L.length = 0;//空表长度为0
}

//读取文件中内容并赋值给SqList
void SqListInput(SqList &L, char filename[]) {
    //与源代码同级目录下的文件filename中输入数据,把数据读入到线性表L中
    int i = 0;
    fstream file;            //构造fstream类的对象file,你可以理解为是一个有操作的ADT
    file.open(filename);    //使用file对象中的open操作打开filename中的文件
    if(!file) {            //如果没见不存在则返回空,输出找不到文件的提示信息
        cout << "未找到"<<filename<<"文件,无法打开!" << endl;
        exit(ERROR);
    }
    while (!file.eof())
        //使用file对象中判断文件中数据是否结束的方法eof。如果到达文件结尾返回true,否则false
    {
        file >> L.elem[i];    //文件中的数据流式输入到线性表中
        i++;
    }
    L.length = i;            //更新线性表表长
}

//输出SqList
void SqListOutPut(SqList L) {
    int i;
    for(i=0; i<L.length; i++) {
        cout << L.elem[i] << " ";
    }
}

//获取SqList长度
int GetLength(SqList L) {
    return L.length;
}

//获取第i个数据
int GetElem(SqList L,int i) {
    if(i<1||i>L.length) return ERROR;
    ElemType e;
    e = L.elem[i-1];
    return e;
}

//获取第i个数据
//int getElem1(SqList L,int i,ElemType &e)
//{
//    if(i<1||i>L.length) return ERROR;
//    e = L.elem[i-1];
//    return OK;
//}

//获取元素下标
int GetIndex(SqList L,ElemType e) {
    int i;
    for(i=0; i<L.length; i++)
        if(L.elem[i]==e) return i;
    return ERROR;
}

//修改表元素
int ChangeElem(SqList &L,int i,ElemType e) {
    if(i<1||i>L.length)
        return ERROR;
    L.elem[i-1]=e;

    return OK;
}

//在第i个元素插入
int InsertElem(SqList &L,int i,ElemType e) {
    if(i<1||i>L.length+1)
        return ERROR;
    if(L.length==MAXSIZE) //存储空间已满
        return ERROR;
    int j;
    for(j=L.length-1; j>=i-1; j--)
        L.elem[j+1]=L.elem[j];//要插入位置的元素以及它后边的元素后移
    L.elem[i-1]=e;
    ++L.length;
    return OK;
}

//删除表中第i个元素
int DeleteElem(SqList &L,int i) {
    if(i<1||i>L.length)
        return ERROR;
    int j;
    for(j=i; j<L.length; j++)
        L.elem[j-1]=L.elem[j];//被删除元素后边的元素前移
    --L.length; //表长减1
    return OK;
}

int MergeSqList(SqList &LA,SqList &LB,SqList &LC) {
    int i,j,flag;
    if(LA.length==MAXSIZE||LB.length==MAXSIZE) //存储空间已满
        return ERROR;
    LC.length=LA.length+LB.length;
    for(i=0; i<LA.length; i++) {
        LC.elem[i]=LA.elem[i];
    }
    for(i=0; i<LB.length; i++) {
        LC.elem[i+LA.length]=LB.elem[i];
    }
    //冒泡排序
    for(i=0; i<LC.length; i++) {
        for(j=0;j<=i;j++) {
            if(LC.elem[j]>LC.elem[j+1]) {
                flag=LC.elem[j+1];
                LC.elem[j+1]=LC.elem[j];
                LC.elem[j]=flag;
            }
        }
    }
    return OK;
}


int main() {
    //LA表的建立与读取
    SqList LA;
    InitSqList(LA);
    SqListInput(LA, (char*)"ListA.txt");
    cout << "ListA: ";
    SqListOutPut(LA);
    //LB表的建立与读取
    SqList LB;
    InitSqList(LB);
    SqListInput(LB, (char*)"ListB.txt");
    cout << endl<<"ListB: ";
    SqListOutPut(LB);
    //表C的建立与初始化
    SqList LC;
    InitSqList(LC);

    //LA表长
    cout << endl<<"ListA的长度: " << GetLength(LA) << endl;
    //LB表长
    cout << "ListB的长度: " << GetLength(LB) << endl;
    //读取表A中第三个元素
    cout << "ListA中第三个元素: " << GetElem(LA,3) << endl;
    //获取表A中数据为8的下标
    cout << "ListA中元素为5的下标: " << GetIndex(LA,5) << endl;


    //修改表B的第6个元素15为14;
    ChangeElem(LB,6,14);
    cout << "已经将第6个元素值15修改为14,新的线性表LA内容如下:"<< endl;
    SqListOutPut(LB);

    //在LA的第三个元素前插入数据:6 
    InsertElem(LA,3,6);
    cout <<endl<< "在表A的第3个位置前插入元素6, 新的线性表LA内容如下:"<< endl;
    SqListOutPut(LA);

    //删除LA中的第三个元素 
    DeleteElem(LA,3);
    cout <<endl<< "删除表A中的第3个元素,新的线性表LA内容如下:"<<endl;
    SqListOutPut(LA);

    //合并AB表并排序 
    MergeSqList(LA,LB,LC);
    cout <<endl <<"合并两个线性表LA和LB,并保持其元素有序性。合并后新的线性表LC内容如下:"<<endl;
    SqListOutPut(LC);
    
    return 0;
}

题目二实现线性表链式存储操作代码

#include<iostream>
#include<string>
#include<fstream>
#include<iomanip>
using namespace std;

#define OVERFLOW -2
#define ERROR 0
#define OK 1
typedef int Status; //Status 是函数返回值类型,其值是函数结果状态代码。
typedef int ElemType; //ElemType 为可定义的数据类型,此设为int类型

struct Book {
    string id;//ISBN
    string name;//书名
    double price;//定价
};

//LinkNode中存了数据和指向下一个结点的指针地址
typedef struct LinkNode {
    Book data; //数据域
    struct LinkNode *next; //指针域,指向直接后继
} LinkNode, *LinkList;

string head_1, head_2, head_3; //全局变量,记录book.txt表头信息
int length;                    //全局变量,记录链表表长信息

Status InitLinkList_L(LinkList &L) {
    //构造一个空的单向链表L
    L = new LinkNode;
    //相当于L.next
    L->next = NULL;//头结点指针域置空
    return OK;
}


//帮助理解  L->next=(*L).next=head.next=首元结点的地址 而*L表示取指针L所指的地址的内容(也就是头结点)

Status CreateList(LinkList &L,char filename[]) {
    //使用前/后插法从文件book.txt读入图书数据,并写入线性表L中,下面是部分代码需要自己完善
//    LinkNode *p;
    //定义一个 LinkNode的指针head指向L,否则不能对L操作
    LinkNode* head = L,*p;
//    L = new LinkNode;
//    L->next = NULL; //先建立一个带头结点的空链表
    length = 0;
    fstream file;
    file.open(filename);//book.txt文件要放在和源代码文件同级目录下(英文路径)
    if (!file) {
        cout << "未找到"<<filename<<"文件,无法打开!" << endl;
        exit(ERROR);
    }
    file >> head_1 >> head_2 >> head_3;

    while (!file.eof()) {
        p = new LinkNode; //生成新结点
        file >> p->data.id >> p->data.name >> p->data.price; //输入元素值
//        p=p->next;
//        L->data.id = p->data.id;
//        p=L->next;
//        L->next=NULL;
        //方法一,将P赋值给首元结点,然后首元结点的指针后移
        head->next = NULL;//头结点指针域置空
        head->next=p;
        head=head->next;
        //方法二,将P赋值给首元结点,并将p赋值给head,此时head会随着循环不断后移
        //head->next = NULL;//头结点指针域置空
        //head->next = p;
        //head = p;
        length++;

//        L=p;
//        L->next=L->next->next;
//        L->next=p->next;
//        cout<< L->next->data.id <<endl;
//        p=p->next;
//        cout<< L->next->data.name <<endl;
//        cout<< L->next->data.price <<endl;
    }
    file.close();
}//CreateList


//输出OutputLinkList
void OutputLinkList(LinkList &L) {
    LinkNode* p = L->next;
    ElemType e;
    while(p) {
        cout<< p->data.id <<" "<<p->data.name<<" "<<p->data.price<<endl;
        p=p->next;
    }
}


LinkNode *GetElem(LinkList L, int i) {
    //在带头结点的单向链表L中查找第i个元素,返回结点的地址,下面代码需要自己编写
    LinkNode* p=L->next;
    int j=1;
    //j<i控制循环次数
    while(p && j<i) {
        p=p->next;
        ++j;
    }
    return p;
} //GetElem

Status ListInsert(LinkList &L, int i, Book e) { // 单向链表的插入元素,下面代码需要自己编写
    LinkNode* p=L;
    LinkNode* newNode=new LinkNode;
    int j=0;
    while(p && j<i-1) {
        p=p->next;
        ++j;
    }
    if(!p||j>i-1) return ERROR; 
    newNode->data=e;
    newNode->next=p->next;
    p->next=newNode;
    return OK;
} //ListInsert



Status ListDelete(LinkList &L, int i) { //单向链表的删除,下面代码需要自己编写
    LinkNode* p=L;
    int j=0;
    while(p && j<i-1) {
        p=p->next;
        ++j;
    }
    if(!(p->next)||(j>i-1)) return ERROR;
    LinkNode* q=p->next;
    cout<<q<<endl;
    p->next=q->next;
    delete q;
    return OK;
}//ListDelete




int main() {
    int a, choose;
    Book e;
    LinkList L, p;
    cout << "1. 建立\n";
    cout << "2. 输入\n";
    cout << "3. 插入\n";
    cout << "4. 删除\n";
    cout << "5. 输出\n";
    cout << "0. 退出\n\n";

    choose = -1;
    while (choose != 0) {
        cout << "请选择:";
        cin >> choose;
        switch (choose) {
            case 1: //建立一个链表
                if (InitLinkList_L(L))
                    cout << "成功建立链表!\n\n";
                break;
            case 2: //使用前/后插法创建链表
                CreateList(L,(char*)"book.txt");
                cout << "输入 book.txt 信息完毕\n\n";
                break;
            case 3: //链表的插入
                cout <<
                     "请输入两个数分别代表插入的位置和数值(书的信息:编号&书名&价格):";
                cin >> a;
                cin >> e.id >> e.name >> e.price;
                if (ListInsert(L, a, e))
                    cout << "插入成功.\n\n";
                else
                    cout << "插入失败!\n\n";
                break;
            case 4: //链表的删除
                cout << "请输入所要删除的书籍的位置:";
                cin >> a;
                if (ListDelete(L, a))
                    cout << "删除成功!\n\n";
                else
                    cout << "删除失败!\n\n";
                break;
            case 5: //链表的输出
                cout << "当前图书系统信息读出:\n";
                p = L->next;
                if (p)
                    OutputLinkList(L);
                else
                cout << "没有图书信息!\n\n";
                break;
        }
    }
    return 0;
}

运行结果图

题目一运行结果
题目二运行结果

最后修改:2023 年 05 月 15 日 07 : 43 PM
如果觉得此文章有用,请随意打赏