数据结构——基于顺序表实现通讯录

简介: 数据结构——基于顺序表实现通讯录

一、. 基于动态顺序表实现通讯录

1.1  功能要求

1)⾄少能够存储100个⼈的通讯信息


2)能够保存⽤⼾信息:名字、性别、年龄、电话、地址等

3)增加联系⼈信息

4)删除指定联系⼈

5)查找制定联系⼈

6)修改指定联系⼈

7)显⽰联系⼈信息

1.2   思路分析

我们之前创建的顺序表可以实现连续存储数据(类型可以为整型、字符等),但无论是哪种类型,存储信息都比较单一,但是通讯录存储信息比较多,有联系人姓名、性别、年龄等,所以我们把一个联系人的所有信息作为一个整体存储到顺序表,原来我们写的是整型作为数据存储每个数组元素空间,现在转化通讯录,把一个人的所有信息打包变为结构体然后存储到数组元素元素的空间,然后基于顺序表实现通讯录功能。


71060fedf9b655c4e860870f4ae5f541_b8eb34a9d1d6490fb70be9a85edf747b.png


1.3 通讯录的实现

因为我们是基于顺序表实现通讯录,先将顺序表写好


1.3.1 顺序表

1.3.1.1  SeqList.h

#define _CRT_SECURE_NO_WARNINGS
#include<stdlib.h>
//#include"Contact.h"
#define NAME_MAX 100
#define SEX_MAX 10
#define TEL_MAX 15
#define ADDR_AMX 20
struct ContactInfo
{
  char name[NAME_MAX];
  char sex[SEX_MAX];
  int age;
  char tel[TEL_MAX];
  char addr[ADDR_AMX];
};
typedef struct ContactInfo  SLDateType;
typedef struct SeqList
{
  SLDateType* a;
  int size;//空间有效数据
  int capacity;//空间大小
}SL;
//初始化和销毁
void SLInit(SL* ps);
void SLDestory(SL* ps);
//尾插和头插
void SLPushBack(SL* ps, SLDateType x);
void SLPushFront(SL* ps, SLDateType x);
//void SLPrint(SL* ps);
//头删和尾删
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);
//在指定位置之前插入
void SLInsert(SL* ps, int pos, SLDateType x);
//删除指定位置
void SLDel(SL* ps, int pos);


注:这里值得注意的是我们将通讯信息结构体定义在SeqList.h中,然后重命名,后面的顺序表结构也是这样,那为什么不把通讯信息结构体定义在Contact.h,然后再SeqList.h中包含Contact.h,对typedef struct ContactInfo  SLDateType


这样看似没问题,实际会造成重命名的问题,所以我们字书时要规范。


381e435206096ced1103adaaa2078059_9914ffd9e97645b0a741ea357061b961.png


8cf5e890d56ddd7e6367f495382477cb_4c05a98f1250413c8ccc8bed1074dc54.png


输出结果:


677387c4e199e518fc4b8df808dff158_035ab56d82084cd1a5d1cc053ca42a31.png


1.3.1.2  SeqList.c

#define _CRT_SECURE_NO_WARNINGS
#include "SeqList.h"
#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
void SLInit(SL* ps)
{
  ps->a = NULL;
  ps->size = ps->capacity = 0;
}
void SLDestory(SL* ps)
{
  if (ps->a)
    free(ps->a);
  ps->a = NULL;
  ps->size = ps->capacity = 0;
}
int  SLCheckCapacity(SL* ps)
{
  assert(ps);
  int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
  if (ps->size == ps->capacity)//进行扩容
  {
    SLDateType* ret = (SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
    if (ret == NULL)
    {
      perror("realloc fail:");
      return 1;
    }
    ps->a = ret;
    ps->capacity = newcapacity;
  }
}
void SLPushBack(SL* ps, SLDateType x)//1.若空间足够,进行插入  2.若空间不够,进行扩容(以1.5或2倍原来大小进行扩容)
{
  assert(ps);
  SLCheckCapacity(ps);
  ps->a[ps->size] = x;
  ps->size++;
}
//void SLPrint(SL* ps)
//{
//  assert(ps);
//  for (size_t i = 0; i < ps->size; i++)
//  {
//    printf("%d ", ps->a[i]);
//  }
//  printf("\n");
//}
void SLPushFront(SL* ps, SLDateType x)
{
  assert(ps);
  SLCheckCapacity(ps);
  for (size_t i = ps->size; i > 0; i--)
  {
    ps->a[i] = ps->a[i-1];
  }
  ps->a[0] = x;
  ps->size++;
}
bool SLIsEmpty(SL * ps)//若返回值为假,则有数据,反之,则无
{
  assert(ps);
  return ps->size == 0;
}
void SLPopBack(SL* ps)
{
  assert(ps);
  //还需要判断是否有数据
  assert(!SLIsEmpty(ps));
  ps->size--;
}
void SLPopFront(SL* ps)
{
  assert(ps);
  //还需要判断是否有数据
  assert(!SLIsEmpty(ps));
  for (size_t i = 0; i < ps->size-1; i++)
  {
    ps->a[i] = ps->a[i + 1];
  }
  ps->size--;
}
// 在指定位置之前插入
void SLInsert(SL* ps, int pos, SLDateType x)
{
  assert(ps);
  SLCheckCapacity(ps);
  //防止越界访问
  assert(pos>= 0 && pos<= ps->size);//端点位置为头插和尾插
  for (size_t i = ps->size; i >pos; i--)
  {
    ps->a[i] = ps->a[i - 1];
  }
  ps->a[pos] = x;
  ps->size++;
}
//删除指定位置
void SLDel(SL* ps, int pos)
{
  assert(ps);
  assert(!SLIsEmpty(ps));
  assert(pos>= 0 && pos< ps->size);//端点位置为头删和尾删
  for (size_t i = pos; i < ps->size-1; i++)
  {
    ps->a[i] = ps->a[i + 1];
  }
  ps->size--;
}


1.3.2  通讯录的初始化+销毁

1.3.2.1 Contact.h

#define _CRT_SECURE_NO_WARNINGS
typedef  struct ContactInfo CInfo;
typedef struct SeqList Contact;//将顺序表重命名为通讯录(这里只是声明,无需包含Seqlist.h)
//通讯录的初始化和销毁
void ContactInit(Contact* con);
void ContactDestroy(Contact* con);

注:这里没有包含SeqList.h,为什么可以重定义结构体和顺序表呢?


因为这里我们只是声明,没有使用,当在text.c使用时,它就会将Contact.h的CInfo和Contact


展开。


1.3.2.2 Contact.c

#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
#include"SeqList.h"
#include <stdlib.h>
#include<stdio.h>
#include<assert.h>
void ContactInit(Contact* con)
{
  SLInit(con);
}
void ContactDestroy(Contact* con)
{
  SLDestory(con);
}

这里直接借用顺序表实现


1.3.3   通讯录的添加+删除

1.3.3.1 Contact.h

//通讯录的初始化和销毁
void ContactInit(Contact* con);
void ContactDestroy(Contact* con);

1.3.3.2 Contact.c

void ContactAdd(Contact* con)
{
  assert(con);
   CInfo info;
      printf("请输入姓名:\n");
    scanf("%s", info.name);
    printf("请输入性别:\n");
    scanf("%s", info.sex);
    printf("请输入年龄:\n");
    scanf("%d", &info.age);
    printf("请输入电话号码:\n");
    scanf("%s", info.tel);
    printf("请输入地址:\n");
    scanf("%s", info.addr);
    //将数据进行尾插
    SLPushBack(con,info);
}
int FindByName(Contact* con,char name[])
{
  for (int i = 0; i < con->size; i++)
  {
    if (strcmp(con->a[i].name, name)==0)
    {
      return i;
    }
  }
  return -1;
}
void ContactDel(Contact* con)
{
  assert(con);
  char name[NAME_MAX];
  printf("需要删除的姓名:\n");
  scanf("%s", name);
  //先查找该信息位置
  int ret=FindByName(con,name);
  if (ret < 0)
  {
    printf("没找到该联系人\n");
    return 1;
  }
  SLDel(con, ret);//删除指定位置
}


注: info.name这个是数组名,所以不用取地址


1.3.4  查看通讯录

1.3.4.1 Contact.h

//查看通讯录
void ContactShow(Contact* con);

1.3.4.2  Contact.c

void ContactShow(Contact* con)
{
  assert(con);
  assert(con->a);
  printf("%-4s%-4s%-4s%-4s%-4s\n", "姓名", "性别", "年龄", "电话", "住址");
  for (int i = 0; i < con->size;i++)
  {
    printf("%-4s %-4s %-4d%-4s%-4s\n",
      con->a[i].name, con->a[i].sex, con->a[i].age, con->a[i].tel, con->a[i].addr);
  }
}

1.3.5  修改通讯录

1.3.5.1 Contact.h

//修改通讯录
void ContactChange(Contact* con);

1.3.5.2 Contact.c

void ContactChange(Contact* con)
{
  assert(con);
  char name[NAME_MAX];
  printf("需要修改的姓名:\n");
  scanf("%s",name);
  //先查找该信息位置
  int ret = FindByName(con, name);
  if (ret < 0)
  {
    printf("没找到该联系人\n");
    return 1;
  }
  printf("请输入修改的姓名:\n");
  scanf("%s",con->a[ret].name);
  printf("请输入修改的性别:\n");
  scanf("%s", con->a[ret].sex);
  printf("请输入修改的年龄:\n");
  scanf("%d", &con->a[ret].age);
  printf("请输入修改的电话号码:\n");
  scanf("%s", con->a[ret].tel);
  printf("请输入修改的地址:\n");
  scanf("%s", con->a[ret].addr);
  printf("修改成功!\n");
}


1.3.6 查找指定联系人

1.3.6.1 Contact.h

//查找指定联系人
void ContactFind(Contact* con);

1.3.6.2 Contact.c

void ContactFind(Contact* con)
{
  assert(con);
  char name[NAME_MAX];
  printf("需要查找的姓名:\n");
  scanf("%s", name);
  //先查找该信息位置
  int ret = FindByName(con, name);
  if (ret < 0)
  {
    printf("没找到该联系人\n");
    return 1;
  }
  printf("%-4s%-4s%-4d%-4s%-4s\n",
    con->a[ret].name, con->a[ret].sex, con->a[ret].age, con->a[ret].tel, con->a[ret].addr);
}


1.3.7 菜单界面

为方便调用通讯录的各种功能,我们做一个菜单界面


1.3.7 .1 text.c

void menu()
{ 
  printf("******************    通讯录   **********************\n");
  printf("***   1.添加联系人          2.删除联系人       ******\n");
  printf("***   3.修改通讯录          4.查看指定联系人   ******\n");
  printf("***   5.查看通讯录          0.退出通讯录       ******\n");
  printf("*****************************************************\n");
}
int main()
{
  int n = -1;
  Contact con;
   ContactInit(&con);
  do
  {
    menu();
    printf("请输入你的选择;\n");
    scanf("%d", &n);
    switch (n)
    {
    case 1:
      ContactAdd(&con);
      break;
    case 2:
      ContactDel(&con);
      break;
    case 3:
      ContactChange(&con);
      break;
    case 4:
      ContactFind(&con);
      break;
    case 5:
      ContactShow(&con);
      break;
    case 0:
      break;
    default:
      printf("输入错误,请从新输入!\n");
      break;
    }
  }while (n);
  ContactDestroy(&con);
  return 0;
}


1.3.8  测试界面

相关文章
|
2月前
|
存储 编译器 C语言
数据结构-顺序表详解(看这篇就足够了,哈哈哈)
数据结构-顺序表详解(看这篇就足够了,哈哈哈)
70 2
|
1天前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
1月前
|
存储 算法 安全
2024重生之回溯数据结构与算法系列学习之顺序表【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
顺序表的定义和基本操作之插入;删除;按值查找;按位查找等具体详解步骤以及举例说明
|
1月前
|
存储 C语言
【数据结构】顺序表(c语言实现)(附源码)
本文介绍了线性表和顺序表的基本概念及其实现。线性表是一种有限序列,常见的线性表有顺序表、链表、栈、队列等。顺序表是一种基于连续内存地址存储数据的数据结构,其底层逻辑是数组。文章详细讲解了静态顺序表和动态顺序表的区别,并重点介绍了动态顺序表的实现,包括初始化、销毁、打印、增删查改等操作。最后,文章总结了顺序表的时间复杂度和局限性,并预告了后续关于链表的内容。
82 3
|
1月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之顺序表习题精讲【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
顺序表的定义和基本操作之插入;删除;按值查找;按位查找习题精讲等具体详解步骤以及举例说明
|
2月前
|
存储 Java
数据结构第二篇【关于java线性表(顺序表)的基本操作】
数据结构第二篇【关于java线性表(顺序表)的基本操作】
46 6
|
2月前
|
存储 安全 Java
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
28 3
|
2月前
|
存储
数据结构(顺序表)
数据结构(顺序表)
31 0
|
2月前
|
存储 算法
【数据结构】新篇章 -- 顺序表
【数据结构】新篇章 -- 顺序表
23 0
|
2月前
|
存储 测试技术
探索数据结构:顺序表的实现与应用
探索数据结构:顺序表的实现与应用

热门文章

最新文章