数据结构_顺序表_C实现(整型数为例)

// /* 实验一 顺序表及其应用
// 线性表是形如A1, A2, A3,…, AN的一般的数据元素序列表。
// 相应地,可以在表上进行诸如插入元素、删除元素和查找元素等操作。
// 线性表及其所有操作都可以使用数组来实现,即顺序表。本实验实现顺序表和它的一些相关应用。
// 实验目的
// (1)掌握顺序表的基本操作:插入、删除、读取、查找等;
// (2)掌握顺序表的应用;
// (3)掌握上机调试顺序表的基本方法。
// (1)实验内容
// (2)顺序表的实现
// 目标:定义一个可存放整型数据的顺序表,并实现其常用算法。*/
// /* (1)算法填空:根据功能提示,完善下划线处的代码。
// 顺序表数据类型的定义
// 定义相应的结构体数据类型,用来表示顺序表这一数据结构对象。 */
#include<stdio.h>
#include<stdlib.h>
#define MAXLEN 100
typedef struct
{
int elem[MAXLEN]; // 用来存放表元素的数组
int n;// 定义一个变量,记录数组中实际存放的元素的个数
}intVec;
/* (1)初始化顺序表
在使用顺序表之前,初始化其为一个空表。可以通过一个函数实现该操作,
函数接收一个待初始化的顺序表对象的地址作为参数。 */
void InitVec(intVec *pVec)/* 静态数组的初始化十分简单:使表长为0即可 */
{
/**********************************************************
初始化pVec指向的顺序表为空
*********************************************************/
pVec->n = 0; // 设置顺序表中元素的个数为0:空表
return;
}
/* /#!没想到的是,
后面的不良内容竟然影响前头的智能感知(这可以写篇文章啦)
在本文,这段注释之前的语句实际上都是合法的,但不知是功能不够完善还是后头的某些非法语句对前头的智能感知造成混乱)
由此可见,智能感知虽好,但不可被完全牵着鼻子走.(遇到莫名奇妙的提示,可以先把后头的内容全注释掉在看看情况(一部分一部分地往后排查)) */
/* (2)插入元素
在顺序表的某一元素位置之前(上)插入一个新元素。插入位置的允许范围为[1, n+1],(当然前提是线性表总空间size>=n+1)
n为当前的表长。当插入位置为n+1时,表示在表尾插入。 */
int InsertVec(intVec *pVec, int i, int x)
{
/**********************************************************
在pVec指向的顺序表的第i个位置之前插入值为x的新元素
*********************************************************/
int j;
// 1. 判断插入位置是否合法
if (i < 1 || i > pVec->n + 1)
{ // 若插入位置超出了允许范围
return -1;
}
if (pVec->n == MAXLEN)
{ // 若表的存储空间已满
return -1;
}
// 2. 需要移动的元素范围:从插入位置到表尾. 由后往前 依次 把元素 后挪一个位置
for (j = pVec->n; j >= i; j--)
{
pVec->elem[j + 1] = pVec->elem[j];
}
// 3. 把新元素放到插入位置,并且记录元素个数的变量值加1
pVec->elem[i - 1] = x;
pVec->n++;
return i; // 返回插入元素在表中的位置
}
/*
// (3)读取元素
// 读取顺序表中某一位置处的元素。读取位置必须在表的长度范围之内,即[1, n],n为当前的表长。
*/
int GetVec(intVec *pVec, int i)
{
/**********************************************************
读取pVec指向的顺序表的第i个位置处的元素
*********************************************************/
// 1. 判断读取位置是否在表的长度范围内
// 若读取位置非法,可通过exit(0) 退出
{
if (i < 1 || i > pVec->n)
exit(0);
}
// 2. 返回表中第i个元素的值
{
return pVec->elem[i - 1];
}
}
/* (4)调试
使用上述操作,完成下面代码,运行并调试程序。 */
void print(intVec *pVec);
int DeleteVec(intVec *pVec, int i);
int FindVec(intVec *pVec, int x);
int LengthVec(intVec *pVec);
int main()
{
intVec a; // 定义一个顺序表对象
// 1. 初始化该顺序表为空表
{
InitVec(&a);
}
// 2. 用户输入若干个整数,并依次插入到该顺序表中
{
int x;
int i = 1;
while (scanf("%d", &x) != EOF)//注意&x
{
if (i <= a.n + 1)/* 放到while里用&& */
{
InsertVec(&a, i, x);
i++;
}
}
}//结束链表素材构建与填充.
// 3. 由后往前,依次读取并输出顺序表中每个位置处的元素
{
printf("输入数据为:1 2 3 4 5\n");
printf("输出为:");
int i = a.n;
for (; i > 0; i--)
printf("%d ",GetVec(&a,i));
printf("\n");
}
/* 调试DeleteVec() */
DeleteVec(&a,3);
printf("调试DeleteVec(),输入i=3,输出为:\n");
print(&a);
printf("\n");
/* 调试FindVec()函数: */
printf("调试FindVec(),输入x=3:\n");
printf("%d",FindVec(&a,3));
printf("\n");
/* 调试LengthVec()函数: */
printf("调试LengthVec(),求表a的长度,输出为:%d\n",LengthVec(&a));
printf("\n");
}
/* 构建print函数 */
void print(intVec *pVec)
{
int GetVec(intVec *pVec, int i);
printf("输出结果为:\n");
int i = pVec->n;
for (; i > 0; i--)
printf("%d ", GetVec(pVec, i));
}
/*
(2)算法练习:根据功能提示,实现算法。
(5)删除元素
删除顺序表中某一位置处的元素。待删除元素位置的允许范围为[1, n],
n为当前的表长。算法实现提示:
1)检查待删除元素的位置是否合法;
2)从待删除元素的后一位置到表尾,依次把元素前挪一个位置,实现对指定位置元素的删除;
3)表中元素个数减1。如删除成功,返回元素位置;否则返回-1。函数原型如下: */
/**********************************************************
删除pVec指向的顺序表的第i个位置处的元素
*********************************************************/
int DeleteVec(intVec *pVec, int i)
{
int k;
if(i<1 ||i>pVec->n )/* 1)检查待删除元素的位置是否合法; */
{
printf("pos值越界,不能进行删除操作! ");
return -1;/* 删除失败,返回-1 */
}
/* 从待删除元素的后一位置到表尾,依次把元素前挪一个位置,实现对指定位置元素的删除; */
for(k = i;k<pVec->n;k++)
{
pVec->elem[k-1] = pVec->elem[k];
}
pVec->n--;/* 表中元素个数减1 */
return i;/* 返回元素位置 */
}
/*
(6)查找元素
在顺序表中查找与某给定值相等的元素。如找到,返回元素位置;否则,返回-1。函数原型如下: */
/**********************************************************
在pVec指向的顺序表中查找值为x的元素
*********************************************************/
int FindVec(intVec *pVec, int x)
{
int i;//辅助变量
for(i=0;i<pVec->n;i++)
{
if(pVec->elem[i] == x)
{
return i + 1;/* 返回元素位置 */
}
}
printf("不存在值为%d的元素或该元素已被删除.",x);
return -1;//未能找到与x相等的元素,返回-1;
}
/*
(7)计算表长度
计算顺序表中的元素个数。函数原型如下: */
/**********************************************************
计算pVec指向的顺序表中的元素个数
*********************************************************/
int LengthVec(intVec *pVec)
{
return pVec->n;
}
/*(8)调试
构建测试数据,在主函数中调用上述所有操作,运行并调试程序。
(3)思考
(1)动态数组(静态链表)
在当前的顺序表数据类型定义中,我们使用静态数组来存放元素,因而一个顺序表最多只能存放MAXLEN个元素。
为了存放更多元素,就需要能够对存放空间进行扩展。为了实现这一目标,我们可以使用动态数组来存放元素。
这时,顺序表数据结构类型可以定义如下: */
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct
{
int* elem; // 指向用来存放表元素的动态数组空间
int size; // 表明动态数组空间的大小
int n; // 定义一个变量,记录数组中实际存放的元素的个数
} intVec;
// /* 初始化时,为顺序表开辟一个固定大小的数组空间。当插入新元素时,
// 如果表存储空间已满,则重新开辟一个更大的数组空间(通常为原空间的两倍大小),
// 把原数组空间中存储的元素拷贝到新数组空间中,并用新数组空间代替原数组空间作为顺序表的存储空间,
// 进而可以把新元素放入到顺序表中。
// 尝试实现基于动态数组的顺序表及其常用算法。
// (2)顺序表的应用
// 目标:能够利用顺序表来解决一些实际应用问题。
// (1)集合求并
// 定义两个顺序表对象LA和LB,用户输入两组整数集合数据,并分别依次插入到顺序表LA和LB中。
// 实现算法,合并LA和LB中的数据,并把合并后的数据存放到LA中。
//最后,依次读取并输出LA中的数据元素。
void againMalloc(intVec* L);
void initList(intVec* L, int ms);
void insert_last_list(intVec* L, int x);
int search(intVec* LA, int e);
void UnionSet(intVec* LA, intVec* LB);
void batchInsertList(intVec* L);
void print(intVec* L);
void intersectionSet(intVec* LA, intVec* LB, intVec* LC);
int main()
{
intVec LA, LB;
intVec LC;
printf("LA表的输入为:1 2 3 4 5 6 -1\n");
batchInsertList(&LA);
printf("LB表的输入为:3 4 5 6 7 8 9 -1 \n");
batchInsertList(&LB);
printf("测试并集函数UnionSet()\n");
UnionSet(&LA, &LB);
printf("并集结果LA:\n");
print(&LA);
//printf("测试交集函数intersection()\n");
//initList(&LC,5);/*单独初始化LC表*/
//intersectionSet(&LA, &LB, &LC);
//printf("交集结果LC:\n");
//print(&LC);
}
//顺序表的输出比链表的输出要简单些.
void print(intVec* L)
{
int i = 0;
for (i = 0; i < L->n; i++)
{
printf("%d ", L->elem[i]);
}
}
/*批量插入(初始化并等待键盘输入)元素到顺序表中*/
void batchInsertList(intVec* L)
{
int ms = 20;
int i=0;
initList(L, ms);
printf("向顺序表里插入元素:\n");
scanf("%d", &i);
while (i != -1)/* -1作为结束输入的标志 */
{
insert_last_list(L, i);
scanf("%d", &i);
}
}
/* 向线性表L中第pos个元素插入x,若插入成功返回1,否则返回0 */
int insertPosList(intVec* L, int pos, int x)/* 比insert_last_list()使用范围更广更强大 */
{
int i;
/* 是否越界 */
if (pos < 1 || pos > L->n + 1)
{
/* "pos越界,插入失败,返回0; */
return 0;
}
/* 是否要拓宽空间 */
if (L->n == L->size)
{
againMalloc(L);
}/* 确保空间足够/仍然不够则会立即结束函数.againmalloc */
for (i = L->n - 1; i >= pos - 1; i--)
{
L->elem[i + 1] = L->elem[i];
}/* 已经腾出位置了 */
L->elem[pos - 1] = x;/* 执行插入 */
L->n++;/* 修正表长 */
return 1;/* 插入成功返回1 */
}
// 合并两个顺序表的算法可通过如下函数实现: */
void UnionSet(intVec* LA, intVec* LB)
{
/**********************************************************
合并LA和LB所指向的两个顺序表对象中的数据,并把合并后的数据存放于LA中
*********************************************************/
int nA, nB, i, e;
nA = LA->n; // 顺序表LA中的元素个数
nB = LB->n; // 顺序表LB中的元素个数
// 逐个读取LB中的元素:若该元素不在LA中,则把该元素插入到LA中
for (i = 1; i <= nB; i++)/* 外层循环控制条件为待插入元素所在集合(链表)的元素个数 */
{
e = LB->elem[i - 1]; // 读取LB中的第i个元素
if (search(LA, e) == -1)/*时间复杂度为O(n)*/
{
// 若该元素不在LA中
insert_last_list(LA, e); // 把该元素插入到LA的表尾
nA++; // 记录LA中当前的元素个数
}
}
}
/*集合求交集:*/
void intersectionSet(intVec* LA, intVec* LB, intVec* LC)
{
int i = 0;
for (i = 0; i < LA->n; i++)
{
if (search(LB, LA->elem[i]) != -1)
{
insert_last_list(LC, LA->elem[i]);
}
}
}
void insert_last_list(intVec* L, int x)
{
/* 插入表尾的话不用判断越界.但仍然要判断空间是否足够. */
if (L->n == L->size)
{
againMalloc(L);/* 需要重新分配更大空间 */
}
L->elem[L->n] = x;/* 把x插入到表尾 */
L->n++;/* 线性表长度+1 */
}
void againMalloc(intVec* L)
{
int* p = (int*)realloc(L->elem, 2 * L->size * sizeof(int));
if (!p)
{
printf("reallo failured !");
exit(1);
}
L->elem = p;/* 使表头指针指向新分配的链表空间 */
L->size = 2 * L->size;
}
void initList(intVec* L, int ms)/* 参数L届时在main()里头定义一个intVec类型的变量L,然后将该变量的地址&L传入initlist函数即可 */
{
if (ms < 0)
{
printf("maxsize is illegal");
}
L->elem = (int*)malloc(ms * sizeof(int));
if (!L->elem)
{
printf("malloc failured");
exit(1);
}
L->size = ms;/* 设置线性表的空间大小为ms */
L->n = 0; /*表中现有元素数为0 */
}
int search(intVec* LA, int e)
{
int i = 0;
for (i = 0; i < LA->n; i++)
{
if (LA->elem[i] == e)
{
return i;
}
}
return -1;
}
// /*
// (2)集合求交
// 类似地,可以编写两个集合求交程序。定义两个顺序表对象LA和LB,
// 用户输入两组整数集合数据,并分别依次插入到顺序表LA和LB中。实现算法,对LA和LB中的数据进行求交,
// 并将结果存放到一个新的顺序表对象LC中。最后,依次读取并输出LC中的数据元素。两个顺序表的求交算法可通过如下函数实现: */
// /**********************************************************
// 对LA和LB所指向的两个顺序表中的数据进行求交,结果存放于LC中
// *********************************************************/
// void IntersectSet(intVec *LA, intVec *LB, intVec *LC);
// /* (3)综合练习
// 在具体应用程序中,可以使用顺序表来存储和管理数据。这里,要求实现一个简单的整数数据管理系统。基本要求如下:
// (4)构建一个简单的可交互系统,用户可以在系统中插入、删除和查找整数,并可统计系统中的整数个数;
// (5)使用顺序表来存储整数数据; */
posted @   xuchaoxin1375  阅读(12)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2023-09-13 java_从键盘输入一个任意的字符串(如:aaabbababaaaababababa),统计该字符串中长度为i的子串出现次数(i从1开始到上述字符串长度结束)
2023-09-13 matlab_利用在线搜索学习matlab(在线中文文档的使用方法)
2021-09-13 apple icon:view only?duplicate to your drafts to do edit
点击右上角即可分享
微信分享提示