数据结构

(1)定义:相互之间存在一种或多种特定关系的数据元素的集合

(2)逻辑结构分类:

  1. 集合:所有数据在同一集合中,关系平等
  2. 线性:数据和数据之间一对一的关系
  3. 树:一对多(目录)
  4. 图:多对多(地图,网)
(3)物理结构(在内存当中的存储关系)
  1. 顺序存储:数据存放在连续的存储单位中。逻辑关系和物理关系一致
  2. 链式:数据存放的存储单位是随机或任意的,可以连续也可以不连续
struct Per数据元素
{
    char name;//数据项
    int age;
    char phone;
}

struct Per list[100]; //数据对象

数据对象为一个集合——》包含了多个数据元素——》数据元素有多个数据项组成——》数据项由变量组成

(4)数据的类型:ADT(abstruct datatype):是指一组性质相同的值的集合及定义在此集合上的一些操作的总称。

抽象数据类型=数学模型+操作

(5)程序=数据+算法

1.算法

  1. 是解决特定问题求解步骤的描述,计算机中表现为指令的有限序列,每条指令表示一个或多个操作。(函数及函数的调用)
①算法的特征
  1. 输入输出特性:输入是可选的,输出是必须的(可以没有传参)
  2. 有穷性:执行的步骤会自动结束,不能是死循环,并且每一步是在可以接受的时间内完成(不能死循环,并且每一步都可以在接受的时间内完成)
  3. 确定性:同一个输入,会得到唯一的输出
  4. 可行性:每一个步骤都是可以实现的
②算法设计要求
  1. 正确性

    • 语法正确
    • 合法的输入能得到合理的结果
    • 对非法的输入,给出满足要求的规格说明
    • 对精心选择,甚至刁难的测试都能正常运行,结果正确
  2. 可读性:便于交流,阅读,理解(画流程图,给程序备注)

  3. 健壮性:输入非法数据,能进行相应的处理,而不是产生异常

  4. 高效性:存储低,效率高(代码简化)

③算法时间复杂度分析(衡量算法的好坏)

算法时间复杂度是执行这个算法所花时间的度量。

④时间复杂度推导规则:(事前分析法)
  1. 用常数1取代运行时间中的所有加法常数
  2. 在修改后的运行函数中,只保留最高阶项
  3. 如果最高阶存在且不是1,则取除这个项相乘的常数
⑤常见时间复杂度排序

O(1) < O(logn) < O(N) < O(nlogn) < O(n²) (for嵌套)< O(n³) < O(2ⁿ) < O(n!) < O(nⁿ)

时间复杂度越小越好算法越好

// 示例1:基本循环
int i, sum; // 8 
for(10000)    // n次循环
{
    sum = i+sum;  // 2n +3
}
a = c;
b = c;
a = d;
// 时间复杂度:O(n)

// 示例2:数学公式计算
int n;  // 4
n = (n+1)*n/2;  // 4
// 时间复杂度:O(1)

// 示例3:嵌套循环
for(i=0; i<n; i++)  // n次
{
    for(j=0; j<n; j++)  // n次
    {
        // 执行操作
    }
}
// 时间复杂度:O(n²)

线性表:零个或多个数据元素的有限序列

顺序表:存储空间是连续的

特征:支持随机访问--head+5 head[0]   O(1)

劣势:①插入,删除需要整体移动  O(N)

           ②不支持动态存储功能。(空间不能随着使用量自动变化,需要手动修改)

(1)线性表特征

  • 元素之间是有顺序的
  • 如果存在多个元素,第一个元素无前驱,最后一个没有后继
  • 其他的元素只有一个前驱和一个后继
  • 当线性表元素的个数n(n>=0)定义为线性表的长度
  • 当n=0时,为空表
  • 在非空的表中每个元素都有一个确定的位置

(2)线性表的常规操作ADT

typedef struct person
{
    char name[32];
    char sex;
    int age;
    int score;
}DATATYPE;    //给结构体struct person取个别名:DATATYPE

typedef struct list
{
    DATATYPE *head;     //数组指针
    int Tlen;        //数组的容量
    int Clen;        //数组有效元素个数
}Seqlist;            //表头结构
/*
 * 创建顺序表
 * 参数:len - 顺序表的初始容量
 * 返回值:成功返回创建的顺序表指针,失败返回NULL
 */
SeqList *CreateSeqList(int len);

/*
 * 销毁顺序表
 * 参数:list - 要销毁的顺序表指针
 * 返回值:0表示成功,非0表示失败
 */
int DestroySeqList(SeqList *list);

/*
 * 显示顺序表中的所有元素
 * 参数:list - 要显示的顺序表指针
 * 返回值:0表示成功,非0表示失败(如顺序表为空或不存在)
 */
int ShowSeqList(SeqList *list);

/*
 * 在顺序表尾部插入元素
 * 参数:list - 目标顺序表指针;data - 要插入的数据元素
 * 返回值:0表示成功,非0表示失败(如顺序表已满)
 */
int InsertTailSeqList(SeqList *list, DATATYPE data);

/*
 * 判断顺序表是否已满
 * 参数:list - 要判断的顺序表指针
 * 返回值:1表示已满,0表示未满,-1表示参数无效
 */
int IsFullSeqList(SeqList *list);

/*
 * 判断顺序表是否为空
 * 参数:list - 要判断的顺序表指针
 * 返回值:1表示为空,0表示非空,-1表示参数无效
 */
int IsEmptySeqList(SeqList *list);

/*
 * 在顺序表指定位置插入元素
 * 参数:list - 目标顺序表指针;data - 要插入的数据元素;pos - 插入位置(从0开始)
 * 返回值:0表示成功,非0表示失败(如位置无效或表已满)
 */
int InsertPosSeqList(SeqList *list, DATATYPE data, int pos);

/*
 * 在顺序表中查找指定名称的元素
 * 参数:list - 要查找的顺序表指针;name - 要查找的名称字符串
 * 返回值:成功返回元素位置索引(从0开始),失败返回-1
 */
int FindSeqList(SeqList *list, char *name);

/*
 * 修改顺序表中指定名称元素的数据
 * 参数:list - 目标顺序表指针;old - 要修改的元素名称;new - 新的数据
 * 返回值:0表示成功,非0表示失败(如未找到对应元素)
 */
int ModifySeqList(SeqList *list, char *old, DATATYPE new);

/*
 * 删除顺序表中指定名称的元素
 * 参数:list - 目标顺序表指针;name - 要删除的元素名称
 * 返回值:0表示成功,非0表示失败(如未找到对应元素)
 */
int DeleteSeqList(SeqList *list, char *name);

/*
 * 清空顺序表中的所有元素(保留表结构)
 * 参数:list - 要清空的顺序表指针
 * 返回值:0表示成功,非0表示失败
 */
int ClearSeqList(SeqList *list);
相关函数:

代码示例

01typedef.c
typedef unsigned int u32_t; // 定义别名 
#include <string.h>

typedef struct Per 
{
    char name[50];
    int age;
    char phone[50];
} PER;

int main(int argc, char *argv[])
{
    u32_t a;  // 使用别名定义变量
    unsigned int b;  // 直接使用原始类型定义变量

    struct Per per;  // 使用原始结构体名
    strcpy(per.name, "zhangsan"); // 1000
    per.age = 20;

    PER p;  // 使用别名定义结构体变量

    return 0;
}

运行结果:程序正常编译运行,无输出

结构体的引用:①结构体的定义是变量的引用:(per.age)

                         ②结构体定义的是指针的引用:(per->ag)

内存泄露检测工具
sudo apt-get install valgrind
valgrind ./all

seqlist.h

.h:对应的头文件

目的:防止头文件重复包含带来的重复定义问题

格式:

#ifndef _SEQLIST_H_(文件名转换的)
#define _SEQLIST_H_(声明,宏定义)

#endif

#ifndef _SEQLIST_H_
#define _SEQLIST_H_

typedef struct person
{
    char name[32];
    char sex;
    int age;
    int score;
} DATATYPE;

typedef struct list
{
    // 数组指针(指针指向这个存储数据的连续内存:结构体(数组首元素))
    DATATYPE *head;//head:指向数据存储(DATATYPE)的指针,相当于动态数组的首地址
    // 数组的容量
    int tlen;
    // 数组的有效元素个数
    int clen;
} SeqList;

// 创建顺序表
SeqList *CreateSeqList(int len);

// 显示顺序表数据
int ShowSeqList(SeqList *list);

// 顺序表尾插
int InsertTailSeqList(SeqList *list, DATATYPE *data);

// 是否满
int IsFullSeqList(SeqList *list);

// 是否空
int IsEmptySeqList(SeqList *list);

// 按位置插入
int InsertPosSeqList(SeqList *list, DATATYPE *data, int pos);

// 查找顺序表
int FindSeqList(SeqList *list, char *name);

// 修改顺序表
int ModifySeqList(SeqList *list, char *old, DATATYPE *newdata);

// 清空表
int ClearSeqList(SeqList *list);

// 销毁顺序表
int DestroySeqList(SeqList *list);

// 删除一个元素
int DeleteSeqList(SeqList *list, char *name);
//获得有效元素个数
int GetSizeSeqList(SeqList *list);

DATATYPE* GetItemSeqlist(SeqList*list, int pos);

#endif
seqlist.c
#include "seqlist.h"//包入自己写的头文件,用""引用
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
SeqList *CreateSeqList(int len)//创建顺序表
{
    SeqList *sl = malloc(sizeof(SeqList));  // 分配顺序表结构体内存
    //解释sizeof(Seqlist):包含数据存储空间和tlen,clen
    if (NULL == sl)
    {
        perror("CreateSeqList malloc error\n");  // 内存分配失败处理
        return NULL;
    }
    sl->head = malloc(sizeof(DATATYPE) * len);  // 分配数据存储空间
    //解释sizeof(DATATYPE)*len:相当于有len(传入的个数)个DATATYPE数组
    if (NULL == sl->head)
    {
        perror("CreateSeqList malloc2 error\n");  // 数据空间分配失败处理
        return NULL;
    }
    sl->tlen = len;  // 设置总长度
    sl->clen = 0;    // 初始化当前长度为0
    return sl;
//两个结构体的内存空间
}
//list->head:结构名指向结构体中的元素
int InsertTailSeqList(SeqList *list, DATATYPE *data)//顺序表尾插
{
    // list->head[list->clen] =*data;//list->clen代表顺序表的数据当前位置,当前位置的数组下标位置
    if (IsFullSeqList(list))  // 检查是否已满
    {
        printf("seqlist is full\n");  // 已满提示
        return 1;
    }
    /*
    list->head[list->clen]:表示当前顺序表位置
    sizeof(DATATYPE):表示DATATYPE结构体大小
    data是DATAYPE结构体类型
    */
    memcpy(&list->head[list->clen], data, sizeof(DATATYPE));  // 复制数据到尾部
    list->clen++;  // 当前长度加1
    return 0;
}

int IsFullSeqList(SeqList *list)//判断顺序表是否满
{
    return list->clen == list->tlen;  // 判断当前有效长度是否等于数组总容量
}

int ShowSeqList(SeqList *list)//遍历顺序表中的数据
{
    int len = GetSizeSeqList(list);  // 获取当前元素个数
    int i = 0;
    for (i = 0; i < len; ++i)
    {
        //解释list->head[i].name:顺序表名指向结构体元素head,但head(数组的首地址)为指针指向另一个结构体,继续指向结构体中的元素name
        printf("name:%s sex:%c age:%d score:%d\n", list->head[i].name,
               list->head[i].sex, list->head[i].age, list->head[i].score);
    };
    return 0;
}

/**
 * @brief Get the Size Seq List object
 *
 * @param list 被查询的顺序表
 * @return int  顺序表有效元素的个数
 */
int GetSizeSeqList(SeqList *list)
{
    return list->clen;  // 返回当前元素个数
}

int IsEmptySeqList(SeqList *list)//判断当前长度是否为0
{
    return 0 == list->clen;
}

/**
 * @brief 按位置插入元素
 *
 * @param list 待插入的顺序表
 * @param data  需要插入的数据
 * @param pos 顺序表的下标
 * @return int 0 表示成功 1表示失败
 */
int InsertPosSeqList(SeqList *list, DATATYPE *data, int pos)//按位置(pos)插入元素
{
    if (IsFullSeqList(list))  // 检查是否已满
    {
        printf("seqlist is full\n");
        return 1;
    }
    int len = GetSizeSeqList(list);
    if (pos < 0 || pos > len)  // 检查位置是否合法
    {
        printf("pos is incorrect\n");
        return 1;
    }
    // 整体后移,让出位置
    for (int i = list->clen; i > pos; i--)
    {
        // list->head[i] = list->head[i - 1];
        memcpy(&list->head[i], &list->head[i - 1], sizeof(DATATYPE));  // 后移元素
    }
    memcpy(&list->head[pos], data, sizeof(DATATYPE));  // 插入新元素
    list->clen++;  // 当前长度加1
    return 0;
}

/**
 * @brief 按名字查找信息
 *
 * @param list 待查询的顺序表
 * @param name 要查询的人员信息名字
 * @return int 成功的 0>=len-1 失败 -1
 */
int FindSeqList(SeqList *list, char *name)
{
    int len = GetSizeSeqList(list);
    for (int i = 0; i < len; i++)  // 遍历查找
    {
        if (0 == strcmp(list->head[i].name, name))  // 比较名字
        {
            return i;  // 找到返回位置
        }
    }
    return -1;  // 未找到返回-1
}

DATATYPE* GetItemSeqlist(SeqList*list, int pos)// 检查位置是否合法
{
    int len = GetSizeSeqList(list);
    if (pos < 0 || pos > len) 
    {
        printf("pos is incorrect\n");
        return NULL;//返回值为指针类型
    }
    return &list->head[pos];  // 返回指定位置元素的指针
}

int ModifySeqList(SeqList *list, char *oldname, DATATYPE *newdata)//修改元素
{
    int ret = FindSeqList(list, oldname);  // 查找要修改的元素
    if(-1 == ret)  // 未找到
    {
        printf("modify failure...\n");
        return 1;
    }
    memcpy(&list->head[ret], newdata, sizeof(DATATYPE));  // 修改数据
    return 0;
}

// 清空表:原理:将数据重新定位到开头,用新的数据去覆盖
int ClearSeqList(SeqList *list)
{
    list->clen = 0;  // 将当前长度设为0
    return 0;
}

// 销毁顺序表
int DestroySeqList(SeqList *list)
{
    free(list->head);  // 空间使用的是堆,需要释放数据存储空间
    free(list);        // 释放顺序表结构体
    return 0;
}
int DeleteSeqList(SeqList *list, char *name)//删除一个元素
{
    int pos=FindSeqList(list, name);//按名字查找
    if(-1==pos)
    {
        printf("no found per %s\n",name);
        return -1;
    }
    //将该位置之后的说有元素向前移动一位
    int i=0;
    for (i=pos;i<list->clen-1;i++)
    {
        memccpy(&list->head[i],&list->head[i+1],sizeof(DATATYPE));
    }
    list->clen--;//长度减一
    return 0;

}

内存泄漏检测工具(命令):sudo apt-get install valgrind

编译:valgrind  ./all

堆的空间释放顺序:先释放head,在释放顺序表

main.c

#include<stdio.h>
#include<stdlib.h>
#include"seqlist.h"
int	main(int argc, char **argv)
{
    SeqList *s1=CreateSeqList(5);//创建一个顺序表
    DATATYPE data[] = 
    {
        {"zhangsan", 'm', 20, 80},    // 定义测试数据
        {"lisi", 'f', 23, 84},
        {"wangmaizi", 'f', 32, 90},
        {"guanerge", 'm', 50, 91},
        {"liubei", 'm', 51, 92},
    };

    InsertTailSeqList(s1, &data[0]);  // 将data[i]中的数据尾部插入数据
    InsertTailSeqList(s1, &data[1]);    //dat[i]相当于代表二维数组一整排的元素,所以不用在指向data中的元素
    InsertTailSeqList(s1, &data[2]);
    InsertPosSeqList(s1,&data[2],1);
    ShowSeqList(s1);
    char want_name[20]="lisi";
    int ret=FindSeqList(s1, want_name);//找lisi的位置,并把位置放在ret中
    if(-1==ret)
    {
        printf("can't find per %s\n",want_name);
    }else
    {
        DATATYPE *tmp=GetItemSeqlist(s1,ret);//检查位置在数据中是否合法
        printf("find per,%s %d\n",tmp->name,tmp->score);
    }
    ModifySeqList(s1,"list",&data[4]);//修改元素
    ShowSeqList(s1);//遍历
    
    DestroySeqList(s1);//删除顺序表

    //system("pause");
    return 0;
}
}


Makefile:工程管理工具(代替gcc用make编译)

1.第一个版本:

#目标名:依赖文件
#第二行的开头是一个tab
all:main.c seqlist.c
	gcc main.c seqlist.c -o all
clean://clean为清除,重新编译
        //命令 make clean
	rm all

2.第二个版本:

#目标名:依赖文件
#第二行的开头是一个tab
#在一条规则中,$^代表依赖文件  $@代表规则中的目标名
#$^,$@都是Makefile的内部变量
all:main.c seqlist.c
	gcc $^ -o $@   #使用内部变量简化命令
	cp main.c 1.c  #添加复制命令
clean:
	rm all $^     # 删除可执行文件和源文件

3.第三个版本:(最终版本)

# .o 目标文件 
SRC= main.o  # 定义源文件列表
SRC+= seqlist.o
DST=all      # 定义目标文件名
CC=gcc       # 定义编译器
LIB= -lm     # 定义链接库

%.o:%.c
	$(CC) -c $^ -o $@  # 编译规则:将.c文件编译为.o文件

$(DST):$(SRC)
	$(CC) $^ -o $@ $(LIB)  # 链接规则:将.o文件链接为可执行文件
	
clean:
	rm $(DST) *.o  # 清理规则:删除可执行文件和目标文件

顺序表与链表的实现及应用(含字典功能与操作对比)

使用顺序表实现查字典功能
  • 支持连续查询单词,输入 #quit 退出程序。
  • 数据格式示例如下:
seqlist.h

顺序表结构定义及操作接口声明

#ifndef _SEQLIST_H_
#define _SEQLIST_H_

// 数据类型定义:存储单词和释义
typedef struct person {
    char word[50];      // 单词字段,最多50字符
    char mean[512];     // 释义字段,最多512字符
} DATATYPE;

// 顺序表结构体
typedef struct list {
    DATATYPE *head;     // 指向动态数组的指针
    int tlen;           // 数组总容量
    int clen;           // 当前有效元素个数
} SeqList;

// 函数声明
SeqList *CreateSeqList(int len);                     // 创建顺序表
int ShowSeqList(SeqList *list);                      // 显示全部数据
int InsertTailSeqList(SeqList *list, DATATYPE *data); // 尾部插入
int IsFullSeqList(SeqList *list);                    // 判断是否满
int IsEmptySeqList(SeqList *list);                   // 判断是否空
int InsertPosSeqList(SeqList *list, DATATYPE *data, int pos); // 按位置插入
int FindSeqList(SeqList *list, char *name);          // 查找指定单词
int ModifySeqList(SeqList *list, char *old, DATATYPE *newdata); // 修改数据
int ClearSeqList(SeqList *list);                     // 清空顺序表
int DestroySeqList(SeqList *list);                   // 销毁顺序表
int DeleteSeqList(SeqList *list, char *name);        // 删除指定元素
int GetSizeSeqList(SeqList *list);                   // 获取有效元素个数
DATATYPE *GetItemSeqlist(SeqList *list, int pos);    // 获取指定位置元素
int ShowSeqListOne(SeqList *list, int inx);          // 显示单条记录

#endif
seqlist.c
#include "seqlist.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 * 创建顺序表
 * @param len 初始容量
 * @return 成功返回指针,失败返回 NULL
 */
SeqList *CreateSeqList(int len)
{
    SeqList *sl = malloc(sizeof(SeqList));
    if (NULL == sl)
    {
        perror("CreateSeqList malloc error\n");
        return NULL;
    }
    sl->head = malloc(sizeof(DATATYPE) * len);
    if (NULL == sl->head)
    {
        perror("CreateSeqList malloc2 error\n");
        return NULL;
    }
    sl->tlen = len;
    sl->clen = 0;
    return sl;
}

/**
 * 尾部插入数据
 * @param list 目标顺序表
 * @param data 待插入数据
 * @return 0 成功,1 失败(已满)
 */
int InsertTailSeqList(SeqList *list, DATATYPE *data)
{
    if (IsFullSeqList(list))
    {
        printf("seqlist is full\n");
        return 1;
    }
    memcpy(&list->head[list->clen], data, sizeof(DATATYPE)); // 安全拷贝
    list->clen++;
    return 0;
}

/**
 * 判断顺序表是否已满
 * @param list 顺序表
 * @return 1 满,0 未满
 */
int IsFullSeqList(SeqList *list)
{
    return list->clen == list->tlen;
}

/**
 * 显示整个顺序表内容
 * @param list 顺序表
 * @return 0
 */
int ShowSeqList(SeqList *list)
{
    int len = GetSizeSeqList(list);
    for (int i = 0; i < len; ++i)
    {
        printf("word:%s mean:%s\n", list->head[i].word, list->head[i].mean);
    }
    return 0;
}

/**
 * 获取顺序表有效元素个数
 * @param list 顺序表
 * @return 元素个数
 */
int GetSizeSeqList(SeqList *list)
{
    return list->clen;
}

/**
 * 判断顺序表是否为空
 * @param list 顺序表
 * @return 1 空,0 非空
 */
int IsEmptySeqList(SeqList *list)
{
    return 0 == list->clen;
}

/**
 * 在指定位置插入数据
 * @param list 顺序表
 * @param data 待插入数据
 * @param pos 插入位置(0-based)
 * @return 0 成功,1 失败
 */
int InsertPosSeqList(SeqList *list, DATATYPE *data, int pos)
{
    if (IsFullSeqList(list))
    {
        printf("seqlist is full\n");
        return 1;
    }
    int len = GetSizeSeqList(list);
    if (pos < 0 || pos > len)
    {
        printf("pos is incorrect\n");
        return 1;
    }
    // 从后往前移动元素,腾出位置
    for (int i = list->clen; i > pos; i--)
    {
        memcpy(&list->head[i], &list->head[i - 1], sizeof(DATATYPE));
    }
    memcpy(&list->head[pos], data, sizeof(DATATYPE));
    list->clen++;
    return 0;
}

/**
 * 查找指定单词的位置
 * @param list 顺序表
 * @param name 要查找的单词
 * @return 找到返回索引,否则返回 -1
 */
int FindSeqList(SeqList *list, char *name)
{
    int len = GetSizeSeqList(list);
    for (int i = 0; i < len; i++)
    {
        if (0 == strcmp(list->head[i].word, name))
        {
            return i;
        }
    }
    return -1;
}

/**
 * 获取指定位置的元素
 * @param list 顺序表
 * @param pos 位置
 * @return 指向该位置元素的指针,非法位置返回 NULL
 */
DATATYPE* GetItemSeqlist(SeqList* list, int pos)
{
    int len = GetSizeSeqList(list);
    if (pos < 0 || pos >= len)  // 修正:pos 应 < len
    {
        printf("pos is incorrect\n");
        return NULL;
    }
    return &list->head[pos];
}

/**
 * 修改指定单词的数据
 * @param list 顺序表
 * @param oldname 原单词
 * @param newdata 新数据
 * @return 0 成功,1 失败(未找到)
 */
int ModifySeqList(SeqList *list, char *oldname, DATATYPE *newdata)
{
    int ret = FindSeqList(list, oldname);
    if (-1 == ret)
    {
        printf("modify failure...\n");
        return 1;
    }
    memcpy(&list->head[ret], newdata, sizeof(DATATYPE));
    return 0;
}

/**
 * 清空顺序表(不清除内存)
 * @param list 顺序表
 * @return 0
 */
int ClearSeqList(SeqList *list)
{
    list->clen = 0;
    return 0;
}

/**
 * 销毁顺序表并释放内存
 * @param list 顺序表
 * @return 0
 */
int DestroySeqList(SeqList *list)
{
    free(list->head);
    free(list);
    return 0;
}

/**
 * 显示指定位置的一条记录
 * @param list 顺序表
 * @param inx 索引
 * @return 0 成功,1 失败
 */
int ShowSeqListOne(SeqList *list, int inx)
{
    int len = GetSizeSeqList(list);
    if (inx < 0 || inx >= len)  // 修正:inx 应 < len
    {
        printf("pos is incorrect\n");
        return 1;
    }
    printf("word:%s mean:%s\n", list->head[inx].word, list->head[inx].mean);
    return 0;
}

顺序表的实现文件,包含所有接口函数的具体实现。

main.c

主程序:加载字典文件,支持交互式查询

#include <stdio.h>
#include <stdlib.h>
#include "seqlist.h"
#include <string.h>

int main(int argc, char** argv)
{
    FILE* fp = fopen("/home/linux/dict.txt", "r");
    if (NULL == fp)
    {
        perror("fopen");
        return 1;
    }

    SeqList* sl = CreateSeqList(20000);
    if (NULL == sl)
    {
        fprintf(stderr, "CreateSeqList error\n");
        return 1;
    }

    // 从文件逐行读取并构建字典

    // 交互式查询
   // 第一部分:从文件读取数据,解析后存入顺序链表(假设sl是顺序链表结构体指针)
while (1)
    {
        DATATYPE data;
        char *word = NULL;
        char *mean = NULL;
        char linebuf[1024] = {0};

        if (NULL == fgets(linebuf, sizeof(linebuf), fp))
        {
            break;  // 文件读取结束
        }

        word = strtok(linebuf, " ");//strtok 是 C 语言中用于 分割字符串 的函数,作用是按照指定的分隔符,可以 “记住上次切割的位置”
        mean = strtok(NULL, "\r");  // 去除回车符

        strcpy(data.word, word);
        strcpy(data.mean, mean);
        InsertTailSeqList(sl, &data);
    }

    // 交互式查询
    while (1)
    {
        char want_word[50] = {0};
        printf("input word: ");
        fgets(want_word, sizeof(want_word), stdin);  // 输入如 "book\n"
        want_word[strlen(want_word) - 1] = '\0';     // 去掉末尾换行符

        if (0 == strcmp(want_word, "#quit"))
        {
            break;
        }

        int ret = FindSeqList(sl, want_word);
        if (-1 == ret)
        {
            printf("cant find %s\n", want_word);
        }
        else
        {
            ShowSeqListOne(sl, ret);  // 输出释义
        }
    }

    fclose(fp);
    DestroySeqList(sl);  // 释放资源
    return 0;
}

说明:fgets 会保留换行符 \n,因此用 strlen(want_word)-1 可将其替换为 \0,实现去换行。

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐