一、数据结构相关内容
1.1 数据的相关内容
1> 数据:是能够被计算机识别、存储、处理的用于描述客观事实的符号
2> 数据的基本单位:数据元素
数据元素:所谓数据元素就是能够完成描述事物的基本单位。例如24061班的一个学生的信息
3> 数据的最小单位:数据项
数据项:用于组成数据元素的不可分割的最小单位。例如一个学生的学号、性别、成绩...
4> 数据对象:由多个数据元素组成的一个集合称为数据对象。例如:24061整个班级
5> 数据之间的关系:数据项 ==> 数据元素 ==> 数据对象 ==> 数据
1.2 结构
1> 数据结构中,结构分为两部分:逻辑结构、存储结构
2> 逻辑结构:表示数据元素之间的关系
1、集合结构:所有的数据元素之间没有任何关系,仅仅只是被放在同一个集合中。例如:一列公交车上的所有人
2、线性结构:数据元素之间存在一对一的关系。例如:食堂打饭排队
3、树形结构:数据元素之间存在一对多的关系。例如:族谱
4、图型结构:数据元素之间存在多对多的关系。例如:朋友
3> 存储结构:所谓存储结构,就是逻辑结构在物理内存上的映射(内存如何存储多个数据元素)
1、顺序存储:使用一片连续的存储空间,存储上述逻辑结构的元素,特点:逻辑上相邻的元素,物理内存上也连续
2、链式存储:使用多个随机地址空间存储上述逻辑结构的元素,特点:逻辑上相邻的元素,物理内存上不一定相邻
3、索引存储:在存储数据元素时,额外多加一张索引表记录数据元素的位置
4、散列存储(哈希存储):所存储的数据元素的位置与数据元素的关键字有关
4> 数据结构:所谓数据结构,其实就是数据之间存在的一种或多种关系的集合,以及加在该集合上的一组操作(增删改查)
二、线性表
1> 概念:由多个相同特性的数据元素组成的线性结构叫做线性表
2> 特点:除了第一个元素没有前驱,最后一个元素没有后继外,其他的数据元素有且仅有一个前驱和一个后继
3> 线性表的分类:
按存储方式:
顺序表:顺序存储的线性表称为顺序表
链表:链式存储的线性表称为链表
按操作受限的方式:
栈:只允许在同一个端点处进行插入和删除操作的线性表
队列:只允许在异端进行插入和删除操作的线性表
三、顺序表
3.1 顺序表的概念
1> 顺序存储的线性表叫做顺序表
线性表:说明该容器对应的逻辑结构为线性结构
顺序存储:表示存储结构为顺序结构,就是使用连续的存储空间进行操作
2> 连续存储空间:可以使用数组来完成或者使用堆区空间
3> 顺序表的表示方式:除了使用一个连续的内存存储顺序表外,还需要外加一个表示顺序表实际长度的变量完成
4> 对顺序表长度的解析:
1、顺序表的长度能够表示顺序表中实际使用的元素个数
2、也能够表示数组中第一个没有存放数据元素的数组元素下标
3、要遍历整个顺序表时,顺序表的长度是最大上限
5> 顺序表结构体类型
#define MAX 20 //顺序表最大容量
typedef int datatype; //数据元素类型
//定义顺序表结构体类型
typedef struct
{
datatype data[MAX]; //存放顺序表的数组
int len; //顺序表的长度
}SeqList, *SeqListPtr;
3.2 有关顺序表的操作
1> 创建顺序表
1、可以在堆区申请一个顺序表,后面操作时,只需要将该顺序表的起始地址传递即可
2、申请出顺序表的空间后,至少需要对顺序表的长度初始化
//定义顺序表的创建函数
SeqListPtr list_create()
{
//在堆区申请一个顺序表的大小空间
SeqListPtr L = (SeqListPtr)malloc(sizeof(SeqList));
if(NULL == L)
{
printf("创建失败\n");
return NULL;
}
//程序执行至此,表示顺序表创建成功
memset(L->data, 0, sizeof(L->data)); //将数组初始化
L->len = 0; //顺序表长度为0
printf("创建成功\n");
return L;
}
2> 顺序表判空和判断满
1、对于添加顺序表元素的操作而言,需要判断顺序表是否已经满了,如果满了的话,则添加失败
一般情况:len<=MAX 满:len==MAX
2、对于减少顺序表元素的操作而言,需要判断顺序表是否已经空了,如果空了的话,就减少失败
空:len == 0
//判空函数,空返回真,非空返回假
int list_empty(SeqListPtr L)
{
return L->len==0;
}
//判满函数,满返回真,非满返回假
int list_full(SeqListPtr L)
{
return L->len==MAX;
}
3> 向顺序表中添加元素
1、判断条件:如果顺序表已经满了,就不能进行添加操作
2、每次添加的数据放入到顺序表的最后面,也就是放在len所在的位置
3、添加完元素后,需要将长度增加
//添加元素
int list_add(SeqListPtr L, datatype e)
{
//判断逻辑
if(NULL==L || list_full(L))
{
printf("添加失败\n");
return -1;
}
//添加逻辑:将要添加的元素放到最后一个位置
L->data[L->len] = e;
//表的变化
L->len++;
printf("添加成功\n");
return 0;
}
4> 遍历顺序表
1、判断逻辑:表是否合法,表是否为空
2、本质上就是数组的遍历,只是遍历到顺序表的长度结束即可
//遍历顺序表
void list_show(SeqListPtr L)
{
//判断逻辑
if(NULL == L || list_empty(L))
{
printf("遍历失败\n");
return ;
}
//遍历
printf("顺序表中元素分别是:");
for(int i=0; i<L->len; i++)
{
printf("%d\t", L->data[i]);
}
printf("\n");
}
5> 顺序表按位置进行插入元素
1、判断逻辑:顺序表不为空,顺序表不满,要插入位置不能小于0,也不能大于len
2> 插入逻辑:需要将从最后一个元素到要插入位置的元素之间所有元素整体向后移动一格
将新元素放入到要插入位置即可
//定义任意位置插入函数
int list_insert_pos(SeqListPtr L, int pos, datatype e)
{
//判断逻辑
if(NULL==L || list_full(L) || pos<0 || pos>L->len)
{
printf("插入失败\n");
return -1;
}
//腾空逻辑
for(int i=L->len-1; i>=pos; i--)
{
L->data[i+1] = L->data[i];//将前面的元素后移
}
//插入数据
L->data[pos] = e;
//表长变化
L->len++;
printf("插入成功\n");
return 0;
}
6> 顺序表任意位置删除元素
1、判断逻辑:表是否为空、表是否合法、删除位置是否合法
2、需要将要删除位置后面的元素开始到最后一个位置为止,整体前移动一格
//定义任意位置删除函数
int list_delete_pos(SeqListPtr L, int pos)
{
//判断逻辑
if(NULL==L || list_empty(L) || pos<0 || pos>=L->len)
{
printf("删除失败\n");
return -1;
}
//删除逻辑
for(int i=pos+1; i<L->len; i++)
{
L->data[i-1] = L->data[i]; //将元素向前偏移
}
//表长变化
L->len --;
printf("删除成功\n");
return 0;
}
7> 按值进行查找位置函数
//定义按值查找位置函数
int list_search_value(SeqListPtr L, datatype e)
{
//判断逻辑
if(NULL==L || list_empty(L))
{
printf("查找失败\n");
return -1;
}
//遍历整个顺序表
for(int i=0; i<L->len; i++)
{
if(L->data[i] == e)
{
return i; //返回查找到的数据下标
}
}
printf("没找到\n");
return -1;
}
8> 按位置修改函数
//按位置进行修改
int list_update_pos(SeqListPtr L, int pos, datatype e)
{
//判断逻辑
if(NULL==L || pos<0 || pos>=L->len || list_empty(L))
{
printf("修改失败\n");
return -1;
}
//正常进行修改
L->data[pos] = e;
printf("修改成功\n");
return 0;
}
9> 按值修改函数
//按值进行修改
int list_update_value(SeqListPtr L, datatype old_e, datatype new_e)
{
//判断逻辑
if(NULL==L || list_empty(L))
{
printf("修改失败\n");
return -1;
}
//根据旧值找的位置
int res = list_search_value(L, old_e);
if(res == -1)
{
printf("没有要修改的值\n");
return -1;
}
//调用函数完成按位置修改
list_update_pos(L, res, new_e);
printf("修改成功\n");
return 0;
}
3.3 所有代码
1> seqlist.h
#ifndef SEQLIST_H
#define SEQLIST_H
#include<myhead.h>
#define MAX 20 //顺序表最大容量
typedef int datatype; //数据元素类型
//定义顺序表结构体类型
typedef struct
{
datatype data[MAX]; //存放顺序表的数组
int len; //顺序表的长度
}SeqList, *SeqListPtr;
//声明顺序表的创建函数
SeqListPtr list_create();
//判空函数
int list_empty(SeqListPtr L);
//判满函数
int list_full(SeqListPtr L);
//添加元素
int list_add(SeqListPtr L, datatype e);
//遍历顺序表
void list_show(SeqListPtr L);
//定义任意位置插入函数
int list_insert_pos(SeqListPtr L, int pos, datatype e);
//定义任意位置删除函数
int list_delete_pos(SeqListPtr L, int pos);
//定义按值查找位置函数
int list_search_value(SeqListPtr L, datatype e);
//按位置进行修改
int list_update_pos(SeqListPtr L, int pos, datatype e);
//按值进行修改
int list_update_value(SeqListPtr L, datatype old_e, datatype new_e);
#endif
2> seqlist.c
#include"seqlist.h"
//定义顺序表的创建函数
SeqListPtr list_create()
{
//在堆区申请一个顺序表的大小空间
SeqListPtr L = (SeqListPtr)malloc(sizeof(SeqList));
if(NULL == L)
{
printf("创建失败\n");
return NULL;
}
//程序执行至此,表示顺序表创建成功
memset(L->data, 0, sizeof(L->data)); //将数组初始化
L->len = 0; //顺序表长度为0
printf("创建成功\n");
return L;
}
//判空函数,空返回真,非空返回假
int list_empty(SeqListPtr L)
{
return L->len==0;
}
//判满函数,满返回真,非满返回假
int list_full(SeqListPtr L)
{
return L->len==MAX;
}
//添加元素
int list_add(SeqListPtr L, datatype e)
{
//判断逻辑
if(NULL==L || list_full(L))
{
printf("添加失败\n");
return -1;
}
//添加逻辑:将要添加的元素放到最后一个位置
L->data[L->len] = e;
//表的变化
L->len++;
printf("添加成功\n");
return 0;
}
//遍历顺序表
void list_show(SeqListPtr L)
{
//判断逻辑
if(NULL == L || list_empty(L))
{
printf("遍历失败\n");
return ;
}
//遍历
printf("顺序表中元素分别是:");
for(int i=0; i<L->len; i++)
{
printf("%d\t", L->data[i]);
}
printf("\n");
}
//定义任意位置插入函数
int list_insert_pos(SeqListPtr L, int pos, datatype e)
{
//判断逻辑
if(NULL==L || list_full(L) || pos<0 || pos>L->len)
{
printf("插入失败\n");
return -1;
}
//腾空逻辑
for(int i=L->len-1; i>=pos; i--)
{
L->data[i+1] = L->data[i];//将前面的元素后移
}
//插入数据
L->data[pos] = e;
//表长变化
L->len++;
printf("插入成功\n");
return 0;
}
//定义任意位置删除函数
int list_delete_pos(SeqListPtr L, int pos)
{
//判断逻辑
if(NULL==L || list_empty(L) || pos<0 || pos>=L->len)
{
printf("删除失败\n");
return -1;
}
//删除逻辑
for(int i=pos+1; i<L->len; i++)
{
L->data[i-1] = L->data[i]; //将元素向前偏移
}
//表长变化
L->len --;
printf("删除成功\n");
return 0;
}
//定义按值查找位置函数
int list_search_value(SeqListPtr L, datatype e)
{
//判断逻辑
if(NULL==L || list_empty(L))
{
printf("查找失败\n");
return -1;
}
//遍历整个顺序表
for(int i=0; i<L->len; i++)
{
if(L->data[i] == e)
{
return i; //返回查找到的数据下标
}
}
printf("没找到\n");
return -1;
}
//按位置进行修改
int list_update_pos(SeqListPtr L, int pos, datatype e)
{
//判断逻辑
if(NULL==L || pos<0 || pos>=L->len || list_empty(L))
{
printf("修改失败\n");
return -1;
}
//正常进行修改
L->data[pos] = e;
printf("修改成功\n");
return 0;
}
//按值进行修改
int list_update_value(SeqListPtr L, datatype old_e, datatype new_e)
{
//判断逻辑
if(NULL==L || list_empty(L))
{
printf("修改失败\n");
return -1;
}
//根据旧值找的位置
int res = list_search_value(L, old_e);
if(res == -1)
{
printf("没有要修改的值\n");
return -1;
}
//调用函数完成按位置修改
list_update_pos(L, res, new_e);
printf("修改成功\n");
return 0;
}
3> main.c
#include"seqlist.h"
int main(int argc, const char *argv[])
{
//创建一个顺序表
SeqListPtr L = list_create();
if(NULL == L)
{
return -1;
}
//调用添加函数
list_add(L, 520);
list_add(L, 1314);
list_add(L, 999);
list_add(L, 666);
//调用遍历函数
list_show(L);
//调用任意位置插入函数
list_insert_pos(L, 0, 100);
list_insert_pos(L, 2, 100);
list_insert_pos(L, 6, 100);
//输出
list_show(L);
//调用删除函数
list_delete_pos(L, 3);
list_show(L);
//调用查找函数
int res = list_search_value(L, 999);
if(res >= 0)
{
printf("您要找的元素在第%d个位置\n", res+1);
}
//调用按位置修改函数
list_update_pos(L, 0, 1234);
list_show(L);
//调用按值修改函数
list_update_value(L, 999, 888);
list_show(L);
return 0;
}