顺序表的应用

文章目录

  • 目录
    • 1. 基于动态顺序表实现通讯录项目
    • 2.顺序表经典算法
      • 2.1 [移除元素](https://leetcode.cn/problems/remove-element/description/)
      • 2.2 [合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/description/)
    • 3. 顺序表的问题及思考

目录

  • 基于动态顺序表实现通讯录项目
  • 顺序表经典算法
  • 顺序表的问题及思考

1. 基于动态顺序表实现通讯录项目

我们先写一个框架:

//Contact.h#include <stdio.h>//暂时加上
//ConTest.c#include "Contact.h"//通讯录菜单
void menu()
{printf("******************通讯录******************\n");printf("*******1. 添加联系人  2.删除联系人********\n");printf("*******3. 修改联系人  4.查找联系人********\n");printf("*******5. 查看通讯录  0.  退 出   ********\n");printf("******************************************\n");
}int main()
{int op = -1;do{menu();printf("请选择您的操作:\n");scanf("%d", &op);switch (op){case 1://添加联系人break;case 2://删除联系人break;case 3://修改联系人break;case 4://查找联系人break;case 5://查看通讯录break;case 0://退出通讯录printf("通讯录退出中...\n");break;default:break;}} while (op != 0);return 0;
}

接着,我们就可以开始添加具体操作了:

先要创建通讯录数据类型:

//Contact.h#define NAME_MAX 100
#define GENDER_MAX 10
#define TEL_MAX 12
#define ADDR_MAX 100//通讯录数据类型
typedef struct PersonInfo
{char name[NAME_MAX];int age;char gender[GENDER_MAX];char tel[TEL_MAX];char addr[ADDR_MAX];
}Info;

我们要把之前写的顺序表中数组的类型进行替换:

//SeqList.h#include "Contact.h"typedef Info SLDataType;

然后我们写接口:

//Contact.h//通讯录提供的操作typedef struct SeqList Contact;//通讯录的初始化和销毁
void ContactInit(Contact* pcon);//实际初始化的还是顺序表

这里我们想把 SL 换成 Contact,这样看上去更好理解,所以就要 typedef struct SeqList Contact; ,但是要使用struct SeqList 就要 #include “SeqList.h” ,但是这样会出现一个问题:
头文件嵌套问题
解决办法:前置声明

//Contact.h//使用顺序表的前置声明
struct SeqList;typedef struct SeqList Contact;//通讯录提供的操作//通讯录的初始化和销毁
void ContactInit(Contact* pcon);//实际初始化的还是顺序表
void ContactDestroy(Contact* pcon);//增加、删除、修改、查找、查看通讯录
void ContactAdd(Contact* pcon);
void ContactDel(Contact* pcon);
void ContactModify(Contact* pcon);
void ContactFind(Contact* pcon);
void ContactShow(Contact* pcon);

此外,以下代码不再适用,直接注释掉:

//SeqList.c//在顺序表中查找x
//int SLFind(SL* ps, SLDataType x)
//{
//	//加上断言对代码的健壮性更好
//	assert(ps);
//
//	for (int i = 0; i < ps->size; i++)
//	{
//		if (x == ps->arr[i])
//		{
//			return i;
//		}
//	}
//
//	return -1;
//}

因为现在 ps->arr[i] 已经变成一个结构体了,不能直接使用 == 来比较

接下来就是方法的具体实现:

//Contact.c//#include "Contact.h"
#include "SeqList.h"//通讯录的初始化和销毁
//SL* ps
void ContactInit(Contact* pcon)
{SLInit(pcon);
}void ContactDestroy(Contact* pcon)
{SLDestroy(pcon);
}//增加、删除、修改、查找、查看通讯录
void ContactAdd(Contact* pcon)
{//创建联系人结构体变量Info info;printf("请输入联系人姓名:\n");scanf("%s", info.name);printf("请输入联系人年龄:\n");scanf("%d", &info.age);printf("请输入联系人性别:\n");scanf("%s", info.gender);printf("请输入联系人电话:\n");scanf("%s", info.tel);printf("请输入联系人住址:\n");scanf("%s", info.addr);//保存数据到通讯录(顺序表)SLPushBack(pcon, info);
}void ContactShow(Contact* pcon)
{printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");for (int i = 0; i < pcon->size; i++){printf("%s %s %d %s %s\n",pcon->arr[i].name,pcon->arr[i].gender,pcon->arr[i].age,pcon->arr[i].tel,pcon->arr[i].addr);}
}int FindByName(Contact* pcon, char name[])
{for (int i = 0; i < pcon->size; i++){if (0 == strcmp(pcon->arr[i].name, name)){//找到了return i;}}return -1;
}void ContactDel(Contact* pcon)
{//删除之前一定要先查找//找到了,可以删除//找不到,不能执行删除printf("请输入要删除的联系人姓名:\n");char name[NAME_MAX];scanf("%s", name);int findIndex = FindByName(pcon, name);if (findIndex < 0){printf("要删除的联系人不存在!\n");return;}//执行删除操作SLErase(pcon, findIndex);printf("联系人删除成功!\n");
}void ContactModify(Contact* pcon)
{//修改之前要先查找//找到了,执行修改操作//没有找到,不能执行修改操作char name[NAME_MAX];printf("请输入要修改的联系人姓名\n");scanf("%s", name);int findIndex = FindByName(pcon, name);if (findIndex < 0){printf("要修改的联系人不存在!\n");return;}//找到了,执行修改操作printf("请输入姓名:\n");scanf("%s", pcon->arr[findIndex].name);printf("请输入年龄:\n");scanf("%d", &pcon->arr[findIndex].age);printf("请输入性别:\n");scanf("%s", pcon->arr[findIndex].gender);printf("请输入电话:\n");scanf("%s", pcon->arr[findIndex].tel);printf("请输入地址:\n");scanf("%s", pcon->arr[findIndex].addr);printf("联系人修改成功!\n");
}void ContactFind(Contact* pcon)
{char name[NAME_MAX];printf("请输入要查找的用户姓名:\n");scanf("%s", name);int findIndex = FindByName(pcon, name);if (findIndex < 0){printf("该联系人不存在!\n");return;}//找到了,打印一下查找的联系人信息printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");printf("%s %s %d %s %s\n",pcon->arr[findIndex].name,pcon->arr[findIndex].gender,pcon->arr[findIndex].age,pcon->arr[findIndex].tel,pcon->arr[findIndex].addr);
}

完整代码:

//SeqList.h#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "Contact.h"//动态顺序表typedef Info SLDataType;typedef struct SeqList
{SLDataType* arr;//存储数据的底层结构int capacity;//记录顺序表的空间大小int size;//记录顺序表当前有效的数据个数
}SL;//初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);//顺序表的尾部插入
void SLPushBack(SL* ps, SLDataType x);//删除指定位置数据
void SLErase(SL* ps, int pos);
//SeqList.c#include "SeqList.h"//初始化和销毁
void SLInit(SL* ps)
{assert(ps);ps->arr = NULL;ps->size = ps->capacity = 0;
}void SLCheckCapacity(SL* ps)
{if (ps->size == ps->capacity){int newCapacity = 0 == ps->capacity ? 4 : 2 * ps->capacity;SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));if (NULL == tmp){perror("realloc fail!");exit(1);}//扩容成功ps->arr = tmp;ps->capacity = newCapacity;}
}//顺序表的尾部插入
void SLPushBack(SL* ps, SLDataType x)
{assert(ps);//空间不够,扩容SLCheckCapacity(ps);//空间足够,直接插入ps->arr[ps->size++] = x;
}//删除指定位置数据
void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);//pos以后的数据往前挪动一位for (int i = pos; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}void SLDestroy(SL* ps)
{assert(ps);free(ps->arr);ps->arr = NULL;ps->size = ps->capacity = 0;
}
//Contact.h#define NAME_MAX 100
#define GENDER_MAX 10
#define TEL_MAX 12
#define ADDR_MAX 100//通讯录数据类型
typedef struct PersonInfo
{char name[NAME_MAX];int age;char gender[GENDER_MAX];char tel[TEL_MAX];char addr[ADDR_MAX];
}Info;//使用顺序表的前置声明
struct SeqList;typedef struct SeqList Contact;//通讯录提供的操作//通讯录的初始化和销毁
void ContactInit(Contact* pcon);//实际初始化的还是顺序表
void ContactDestroy(Contact* pcon);//增加、删除、修改、查找、查看通讯录
void ContactAdd(Contact* pcon);
void ContactDel(Contact* pcon);
void ContactModify(Contact* pcon);
void ContactFind(Contact* pcon);
void ContactShow(Contact* pcon);
//Contact.c#include "SeqList.h"//通讯录的初始化和销毁
//SL* ps
void ContactInit(Contact* pcon)
{SLInit(pcon);
}void ContactDestroy(Contact* pcon)
{SLDestroy(pcon);
}//增加、删除、修改、查找、查看通讯录
void ContactAdd(Contact* pcon)
{//创建联系人结构体变量Info info;printf("请输入联系人姓名:\n");scanf("%s", info.name);printf("请输入联系人年龄:\n");scanf("%d", &info.age);printf("请输入联系人性别:\n");scanf("%s", info.gender);printf("请输入联系人电话:\n");scanf("%s", info.tel);printf("请输入联系人住址:\n");scanf("%s", info.addr);//保存数据到通讯录(顺序表)SLPushBack(pcon, info);
}int FindByName(Contact* pcon, char name[])
{for (int i = 0; i < pcon->size; i++){if (0 == strcmp(pcon->arr[i].name, name)){//找到了return i;}}return -1;
}void ContactDel(Contact* pcon)
{//删除之前一定要先查找//找到了,可以删除//找不到,不能执行删除printf("请输入要删除的联系人姓名:\n");char name[NAME_MAX];scanf("%s", name);int findIndex = FindByName(pcon, name);if (findIndex < 0){printf("要删除的联系人不存在!\n");return;}//执行删除操作SLErase(pcon, findIndex);printf("联系人删除成功!\n");
}void ContactModify(Contact* pcon)
{//修改之前要先查找//找到了,执行修改操作//没有找到,不能执行修改操作char name[NAME_MAX];printf("请输入要修改的联系人姓名\n");scanf("%s", name);int findIndex = FindByName(pcon, name);if (findIndex < 0){printf("要修改的联系人不存在!\n");return;}//找到了,执行修改操作printf("请输入姓名:\n");scanf("%s", pcon->arr[findIndex].name);printf("请输入年龄:\n");scanf("%d", &pcon->arr[findIndex].age);printf("请输入性别:\n");scanf("%s", pcon->arr[findIndex].gender);printf("请输入电话:\n");scanf("%s", pcon->arr[findIndex].tel);printf("请输入地址:\n");scanf("%s", pcon->arr[findIndex].addr);printf("联系人修改成功!\n");
}void ContactFind(Contact* pcon)
{char name[NAME_MAX];printf("请输入要查找的用户姓名:\n");scanf("%s", name);int findIndex = FindByName(pcon, name);if (findIndex < 0){printf("该联系人不存在!\n");return;}//找到了,打印一下查找的联系人信息printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");printf("%s %s %d %s %s\n",pcon->arr[findIndex].name,pcon->arr[findIndex].gender,pcon->arr[findIndex].age,pcon->arr[findIndex].tel,pcon->arr[findIndex].addr);
}void ContactShow(Contact* pcon)
{printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");for (int i = 0; i < pcon->size; i++){printf("%s %s %d %s %s\n",pcon->arr[i].name,pcon->arr[i].gender,pcon->arr[i].age,pcon->arr[i].tel,pcon->arr[i].addr);}
}
//ConTest.c#include "SeqList.h"//通讯录菜单
void menu()
{printf("******************通讯录******************\n");printf("*******1. 添加联系人  2.删除联系人********\n");printf("*******3. 修改联系人  4.查找联系人********\n");printf("*******5. 查看通讯录  0.  退 出   ********\n");printf("******************************************\n");
}int main()
{int op = -1;//创建通讯录结构对象Contact con;ContactInit(&con);do{menu();printf("请选择您的操作:\n");scanf("%d", &op);switch (op){case 1://添加联系人ContactAdd(&con);break;case 2://删除联系人ContactDel(&con);break;case 3://修改联系人ContactModify(&con);break;case 4://查找联系人ContactFind(&con);break;case 5://查看通讯录ContactShow(&con);break;case 0://退出通讯录printf("通讯录退出中...\n");break;default:break;}} while (op != 0);//销毁通讯录ContactDestroy(&con);return 0;
}

2.顺序表经典算法

2.1 移除元素

移除元素

int removeElement(int* nums, int numsSize, int val)
{//定义两个变量int src = 0, dst = 0;while (src < numsSize){//nums[src] == val,src++//否则赋值,src和dst都++if (nums[src] == val){src++;}else{//说明src指向位置的值不等于valnums[dst] = nums[src];dst++;src++;}}//此时dst的值刚好是数组的新长度return dst;
}

2.2 合并两个有序数组

合并两个有序数组

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{int l1 = m - 1;int l2 = n - 1;int l3 = m + n - 1;while (l1 >= 0 && l2 >= 0){//从后往前比大小if (nums1[l1] > nums2[l2]){nums1[l3--] = nums1[l1--];}else{nums1[l3--] = nums2[l2--];}}//要么是l1 < 0,要么是l2 < 0while (l2 >= 0){nums1[l3--] = nums2[l2--];}
}

3. 顺序表的问题及思考

  1. 中间/头部的插入删除,时间复杂度为O(N)
  2. 增容需要申请新空间,拷贝数据,释放旧空间,会有不小的消耗
  3. 增容一般是呈2倍的增长,势必会有⼀定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。

是否存在一种数据结构,能够解决以上顺序表表现出来的问题:

  1. 中间/头部的插入删除,可以一步到位,不需要挪动数据
  2. 不需要扩容
  3. 不会造成空间浪费

链表这种数据结构就可以解决这些问题,我们在下一篇中就会进行介绍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/595583.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

随机森林、AdaBoost 和 XGBoost 三者之间的主要区别

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 集成学习是一种强大的机器学习范式&#xff0c;它通过构建并结合多个学习器来提高预测性能。其中&#xff0c;随机森林、AdaBoost 和 XGBoost 是集成学习领域中著名且广泛应用的方法。尽管这些方法共享…

比selenium体验更好的ui自动化测试工具: cypress介绍

话说 Cypress is a next generation front end testing tool built for the modern web. And Cypress can test anything that runs in a browser.Cypress consists of a free, open source, locally installed Test Runner and a Dashboard Service for recording your tests.…

os.listdir()bug总结

今天测试出一个神奇的bug&#xff0c;算是教训吧&#xff0c;找了两天不知道问题在哪&#xff0c;最后才发现问题出现在这 原始文件夹显示 os.listdir()结果乱序 import os base_path "./file/"files os.listdir(base_path)print(files)问题原因 解决办法(排序)

蓝桥杯第十四届C++A组(未完)

【规律题】平方差 题目描述 给定 L, R&#xff0c;问 L ≤ x ≤ R 中有多少个数 x 满足存在整数 y,z 使得 。 输入格式 输入一行包含两个整数 L, R&#xff0c;用一个空格分隔。 输出格式 输出一行包含一个整数满足题目给定条件的 x 的数量。 样例输入 1 5 样例输出 …

文件怎么做成二维码图片?怎么用手机扫描二维码下载文件?

文件如何生成二维码图片&#xff1f;随着互联网的不断发展&#xff0c;用二维码来传递内容已经成为一种很常用的方式&#xff0c;其他人可以通过手机扫描生成二维码的方式来查看或者下载文件内容&#xff0c;有效提升文件传输的效率和速度。 现在制作活码类型的二维码可以在图…

JVM基础:类的生命周期详解

JDK版本&#xff1a;jdk8 IDEA版本&#xff1a;IntelliJ IDEA 2022.1.3 文章目录 一. 生命周期概述二. 加载阶段(Loading)2.1 加载步骤2.2 查看内存中的对象 三. 连接阶段(Linking)3.1 连接之验证3.2 连接之准备3.3 连接阶段之解析 四. 初始化阶段(Initialization)4.1 单个类的…

官方竞价排名是否对SEO自然排名有影响?

很多站长有疑问&#xff0c;如果使用搜索引擎官方的SEM竞价&#xff0c;是否对之前做的SEO自然优化排名有影响。这个问题我自己也有疑问。 因为很多站长认为是起绝对反作用&#xff0c;什么只要用了竞价&#xff0c;停止之后&#xff0c;原本很好的排名都会掉光。我们不否定一…

idea开发 java web 酒店推荐系统bootstrap框架开发协同过滤算法web结构java编程计算机网页

一、源码特点 java 酒店推荐推荐系统是一套完善的完整信息系统&#xff0c;结合java web开发和bootstrap UI框架完成本系统 采用协同过滤算法进行推荐 &#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式…

JAVA8 新特性StreamAPI使用(二)

一、使用StreamAPI&#xff0c;&#xff08;基于数据模型——客户、订单和商品&#xff0c;实体关系图如下&#xff0c;客户可以有多个订单&#xff0c;是一对多的关系&#xff0c;而产品和订单的关系是多对多的&#xff09;需求如下&#xff1a; 二、Stream API思维导图 三、需…

用C/C++加Easyx实现俄罗斯方块游戏(爆肝4万字,完全免费)

前言 相信大家一定玩过俄罗斯方块这款小游戏&#xff0c;简单容易上手是老少皆宜的小游戏&#xff0c;今天大家就跟着我来实现这个小游戏吧&#xff01;让自己学的C语言有用武之地。 为了让俄罗斯方块的开发更为简单些&#xff0c;图像更为丰富&#xff0c;在这里就利用了Easyx…

故障诊断 | 一文解决,PLS偏最小二乘法的故障诊断(Matlab)

效果一览 文章概述 故障诊断 | 一文解决,PLS偏最小二乘法的故障诊断(Matlab) 模型描述 偏最小二乘法(Partial Least Squares, PLS)是一种统计建模方法,用于建立变量之间的线性关系模型。它是对多元线性回归方法的扩展,特别适用于处理高维数据和具有多重共线性的数据集。…

Java面向对象进阶基础知识

面向对象进阶 static 静态变量 被该类的所有的对象共享 不属于对象,属于类 随着类的加载而加载,优先于对象存在 类名调用(推荐) 对象名调用 static的注意事项 静态方法中没有this关键字 静态方法,只能访问静态 非静态方法可以访问所有 在Java中&#xff0c;static关…