线性结构
前言
//嵌入式入门必学, //文章中用到的Linux版本——Ubuntu18.04 //本文章旨在通过项目程序,掌握线性结构-动态顺序表
什么是数据结构
//数据:现实生活中的一切事物 //结构:逻辑结构和存储结构 //研究的是数据的逻辑结构、存储结构及其操作(创销增删改查)
为什么学习数据结构
//学习C语言目的是:写程序 //而学习数据结构的目的是:高效的写程序
结构
逻辑结构
存储结构
顺序存储: 逻辑上连续的数据,在物理空间上也连续 ——(计算机上) 链式存储: 逻辑上连续的数据,在物理空间上不一定连续 ——(计算机上) 索引存储: 有索引表,索引表占有一定的空间 根据索引表找数据,插入数据、删除数据要更新索引表 索引表本身占空间 插入数据和删除数据之后要更新索引表,时间开销大,查找方便,插入和删除不方便 ——(数据结构上) 哈希存储: 根据关键字就能定位到记录本身,查询方便,插入删除方便 哈希函数设置的不合理,哈希存储会降维成索引存储 ——(数据结构上)
项目
动态顺序表
1、创建目录
创建ListBak目录,包含子目录bin目录、include目录、obj目录、src目录、子文件Makefile文件
详细如下图
2、头文件
myhead.h
#ifndef _MYHEAD_H
#define _MYHEAD_H
//相关的头文件
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//文件相关
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
//相关的定义
//定义数据类型
/*
typedef struct student
{
char name[20];
char id[20];
char add[20];
int age;
}data_type;
*/
//简化操作,将int data_type
typedef int data_type;
//定义顺序表
typedef struct list
{
data_type *Data;
int size;
int count;
}List;
//返回值
typedef enum ret{
/* member*/
LIST_NULL = -4,
POS_ERR,
LIST_FULL,
LIST_EMPTY,
OK,
} ret_e;
//相关函数声明
//打印菜单
//函数返回值:获取的选项
int Menu(void);
//函数定义:
//函数功能:创建顺序表
//函数参数:void
//函数返回值:成功返回表的地址,失败返回NULL
List *CreateList(void);
//函数功能:插入元素
//函数参数:给谁插入,插入的位置,插入的值
//函数返回值:成功返回OK,失败返回失败原因(错误信息)
int InsertItem(List *pList,int pos,data_type item);
//函数功能:显示所有的元素
//函数参数:被显示元素的表
//函数返回值:成功返回OK,失败返回失败原因
int ShowList(List *pList);
//函数功能:查询元素
//函数参数:查哪个表,表的元素
//函数返回值:成功返回查到的元素,失败返回失败原因
int Search(List *pList,data_type item);
//函数功能:删除元素
//函数参数:被删除元素的表,删除的位置,删除的值
//函数返回值:成功返回OK,失败返回失败原因
int DeleteItem(List *pList,int pos,data_type *item);
//函数功能:销毁空间
//函数参数:要销毁的表
//函数返回值:成功返回OK,失败返回失败原因
int DestoryList(List **pList);
//函数功能:保存
//函数参数:要保存的表
//函数返回值:成功返回OK,失败返回失败原因
int Save(List *pList);
//函数功能:导入
//函数参数:
//函数返回值:
List *LoadList(List *pList);
//函数功能:修改元素
//函数参数:被修改元素的表,旧元素,新元素
//函数返回值:成功返回OK,失败返回失败原因
int ModifyItem(List *pList,data_type old_item,data_type new_item);
#endif
3、源代码文件
main.c
#include"../include/myhead.h"
int main(int argc, const char *argv[])
{
//表
List *pList = NULL;
//定义选项
int opt = 0;
//定义插入位置
int pos = 0;
//定义插入元素
data_type item = 0;
//接返回值
int ret = 0;
//定义修改函数旧元素,新元素变量
data_type old_item = 0;
data_type new_item = 0;
//打印目录 Menu()
while(1)
{
opt = Menu();
if(-1 == opt) break;//退出
switch(opt)
{
case 1:
//insert
printf("请输入要插入的位置和元素,尾插(pos=-1):");
scanf("%d%d",&pos,&item);
ret = InsertItem(pList,pos,item);
break;
case 2:
//delete
printf("请输入要删除的位置(尾删 -1):");
scanf("%d",&pos);//小Bug:用户输入5的位置,实际删除6的位置
ret = DeleteItem(pList,pos,&item);
if(!ret) printf("删除的:%d:\n",item);
break;
case 3:
//search
printf("请输入要查询的元素:");
scanf("%d",&item);
ret = Search(pList,item);
break;
case 4:
//modify(修改元素)
printf("请输入被修改的元素与修改后的元素:");
scanf("%d %d",&old_item,&new_item);
ret = ModifyItem(pList,old_item,new_item);
break;
case 5:
//show
ret = ShowList(pList);
break;
case 6:
//save
ret = Save(pList);
break;
case 7:
//load
pList = LoadList(pList);
break;
case 8:
//destory
printf("main : Before %p\n",pList);
ret = DestoryList(&pList);
printf("main : After %p\n",pList);
break;
case 9:
//创建顺序表
//创建空间
pList = CreateList();
if(!pList) return -1;
printf("pList = %p\n",pList);
printf("pList->size = %d\n",pList->size);
break;
defaut:
puts("请输入有效选项!");
}
switch(ret)
{
case POS_ERR:
puts("POS_ERR");
break;
case LIST_FULL :
puts("LIST_FULL");
//调用扩容的函数
break;
case LIST_NULL:
puts("LIST_NULL");
//重新分配空间
break;
case LIST_EMPTY:
puts("LIST_EMPTY");
break;
}
}
return 0;
}
menu.c
#include"../include/myhead.h"
//打印菜单
//函数返回值:获取的选项
int Menu(void)
{
int opt = 0;
puts("\t\t 1-----插入元素");
puts("\t\t 2-----删除元素");
puts("\t\t 3-----查询元素");
puts("\t\t 4-----修改元素");
puts("\t\t 5-----显示元素");
puts("\t\t 6-----保存");
puts("\t\t 7-----导入");
puts("\t\t 8-----销毁");
puts("\t\t 9-----创建顺序表");
puts("\t\t-1-----退出");
printf("请选择功能:");
scanf("%d",&opt);
return opt;
}
insert.c
#include"../include/myhead.h"
//函数功能:插入元素
//函数参数:给谁插入,插入的位置,插入的值
//函数返回值:成功返回OK,失败返回失败原因(错误信息)
int InsertItem(List *pList,int pos,data_type item)
{
//入参判断
if(!pList) return LIST_NULL;
//判断是否为满
if(pList->count == pList->size) return LIST_FULL;
//判断位置是否合法
if(pos < -1 || pos > pList->count) return POS_ERR;
//插入
//如果 pos = -1 尾插
if(-1 == pos){
pList->Data[pList->count] = item;
//元素个数+1
pList->count++;
return OK;
}
//
//1、移动元素
for(int i = pList->count; i > pos; i--){
pList->Data[i] = pList->Data[i - 1];
}
//2.插入
pList->Data[pos] = item;
//3.count
pList->count ++;
return OK;
}
delete.c
#include"../include/myhead.h"
//函数功能:删除元素
//函数参数:被删除元素的表,删除的位置,删除的值
//函数返回值:成功返回OK,失败返回失败原因
int DeleteItem(List *pList,int pos,data_type *item)
{
//入参判断
if(!pList) return LIST_NULL;
//表为空
if(0 == pList->count) return LIST_EMPTY;
//pos
if(pos < -1 || pos > pList->count - 1) return POS_ERR;
//删除元素
//尾删
if(-1 == pos){
//删的同时把最后一个元素保存
*item = pList->Data[pList->count-1];
//元素的个数 -1
pList->count --;
puts("成功删除最后一个元素\n");
return OK;
}
//正常的删除
//1、保存元素
*item = pList->Data[pos];
//移动元素
for(int i = pos; i < pList->count-1; i++){
pList->Data[i] = pList->Data[i + 1];
}
//个数 -1
pList->count--;
printf("成功删除%d元素\n",*item);
return OK;
}
search.c
#include"../include/myhead.h"
//函数功能:查询元素
//函数参数:查哪个表,表的元素
//函数返回值:成功返回查到的元素,失败返回失败原因
int Search(List *pList,data_type item)
{
//入参判断表是否存在
if(!pList) return LIST_NULL;
//判断表是否为空
if(0 == pList->count) return LIST_EMPTY;
//遍历元素
for(int i = 0; i < pList->count; i++){
if(pList->Data[i] == item){
//找到了,返回元素的位置
puts("表中存在此元素");
return OK;
}
}
//找到了
puts("表中不存在此元素");
return OK;
}
modify.c
#include"../include/myhead.h"
//函数功能:修改元素
//函数参数:被修改元素的表,旧元素,新元素
//函数返回值:成功返回OK,失败返回失败原因
int ModifyItem(List *pList,data_type old_item,data_type new_item)
{
//入参判断
if(!pList) return LIST_NULL;
//如果为空
if(0 == pList->count) return LIST_EMPTY;
//从头到尾遍历元素
for(int i = 0; i < pList->count; i++){
if(pList->Data[i] == old_item){
//找到了
//替换
pList->Data[i] = new_item;
puts("修改成功");
return OK;
}
}
//没找到
puts("查无旧元素");
return OK;
}
show.c
#include"../include/myhead.h"
//函数功能:显示所有的元素
//函数参数:被显示元素的表
//函数返回值:成功返回OK,失败返回失败原因
int ShowList(List *pList)
{
//入参判断
//判断有没有这个表
if(!pList)return LIST_NULL;
//如果为空
if(0 == pList->count) return LIST_EMPTY;
//遍历打印元素
for(int i = 0; i < pList->count; i++){
printf("%d\t",pList->Data[i]);
}
putchar(10);
return OK;
}
save.c
#include"../include/myhead.h"
//函数功能:保存
//函数参数:要保存的表
//函数返回值:成功返回OK,失败返回失败原因
int Save(List *pList)
{
int fd = 0;
//入入参判断
if(!pList) return LIST_NULL;
//打开文件
fd = open("data.txt",O_WRONLY | O_CREAT | O_TRUNC,0664);
//写
write(fd,pList,sizeof(List));
//写存储
write(fd,pList->Data,sizeof(data_type) * pList->size);
//关闭文件
close(fd);
puts("Write Success!");
return OK;
}
load.c
#include"../include/myhead.h"
//函数功能:导入
//函数参数:
//函数返回值:成功返回表的地址,失败返回NULL
List *LoadList(List *pList)
{
int mysize = 1;
//创建空间
//表:用来接收
pList = (List *)malloc(sizeof(List));
//判断空间是否开辟成功
if(!pList){
puts("MALLOC");
return NULL;
}
memset(pList,0,sizeof(List));
pList->Data = (data_type *)malloc(sizeof(data_type) * mysize);//大小,显示计算
pList->size = mysize;
int fd = 0;
fd = open("data.txt",O_RDONLY);
if(fd != -1)//成功打开文件,有原始数据
{
//读数据,获取size和count
read(fd,pList,sizeof(List));
//申请空间
pList->Data = (data_type *)malloc(sizeof(data_type)* pList->size);
if(!pList->Data) return NULL;
//读数据给存储空间
read(fd,pList->Data,sizeof(data_type)*pList->size);
close(fd);
puts("read success!");
return pList;
}
}
destory.c
#include"../include/myhead.h"
//函数功能:销毁空间
//函数参数:要销毁的表
//函数返回值:成功返回OK,失败返回失败原因
int DestoryList(List **pList)
{
//入参判断
printf("删除之前的地址:%p\n",*pList);
if(!(*pList)) return LIST_NULL;
//释放空间
free(*pList);
*pList = NULL;
printf("删除之后的地址:%p\n",*pList);
return OK;
}
creat.c
#include"../include/myhead.h"
//函数定义:
//函数功能:创建顺序表
//函数参数:void
//函数返回值:成功返回表的地址,失败返回NULL
List *CreateList(void)
{
int mysize = 0;//后续的scanf接收表大小
List *pList = NULL; //避免野指针的出现
//创建空间
//表
pList = (List *)malloc(sizeof(List));
//判断空间是否开辟成功,失败打印MALLOC
if(!pList){
puts("MALLOC");
return NULL;//与CreateList函数返回值对应
}
//void *memset(void *s, int c, size_t n);
//s:指向要设置的内存区域的指针。
//c:要设置的值,会被转换为unsigned char类型。
//n:要设置的字节数。
memset(pList,0,sizeof(List));
//开始创建存储空间的大小
printf("请输入大小:");
scanf("%d",&mysize);
//给顺序表的存储空间
pList->Data = (data_type *)malloc(sizeof(data_type) * mysize);//大小,显示计算
//calloc 效率没有malloc高
//初始化顺序表的大小
pList->size = mysize;
return pList;
}
4、Makefile文件
ListBak目录下Makefile文件
All:
make -C ./src/
make -C ./obj/
.PHONY:CLEAN
CLEAN:
rm obj/*.o
rm bin/*
obj目录下Makefile文件
ALL:
gcc *.o -o ../bin/APP
src目录下Makefile文件
ALL:../obj/main.o ../obj/menu.o ../obj/creat.o ../obj/insert.o ../obj/show.o ../obj/search.o ../obj/delete.o ../obj/destory.o ../obj/save.o ../obj/load.o ../obj/modify.o
../obj/main.o:main.c
gcc -c $< -o $@
../obj/menu.o:menu.c
gcc -c $< -o $@
../obj/creat.o:creat.c
gcc -c $< -o $@
../obj/insert.o:insert.c
gcc -c $< -o $@
../obj/show.o:show.c
gcc -c $< -o $@
../obj/search.o:search.c
gcc -c $< -o $@
../obj/delete.o:delete.c
gcc -c $< -o $@
../obj/destory.o:destory.c
gcc -c $< -o $@
../obj/save.o:save.c
gcc -c $< -o $@
../obj/load.o:load.c
gcc -c $< -o $@
../obj/modify.o:modify.c
gcc -c $< -o $@
后续为大家带来全注释版本,持续更新……