一、课程体系
概念
顺序表,单链表,单向循环表,双向循环表,队列,栈
树
图
算法:
查找算法,排序算法
二、为什么要学习数据结构
1.程序 = 数据结构 +算法
数据结构体是写代码非常重要的东西,也是一门基础课程
2.任何一门编程语言,数据结构都是非常重要的组成部分
比如c++里面的STL(标准模板库)
数据库的本质就是数据结构的内容编写的
数据的图的遍历算法就是人工智能的基础
红黑树会在驱动中体现
三、数据结构的概念
3.1 基本概念
数据结构:
数据:研究对象
结构:数据之间的关系
数据结构主要就是研究数据与数据之间的关系
在实际开发中,数据结构主要用于搞清楚数据之间的关系之后在内存中临时存储数据
3.2 数据结构的定义
数据结构主要研究的是数据的逻辑关系和存储关系以及操作
3.3 逻辑关系
逻辑关系主要指的是数据之间在逻辑上的关系,主要指的是领接关系
逻辑关系在考虑数据之间关系的时候会涉及到直接前驱和直接后继的概念
线性关系:一对一的关系,任何一个数据只能有一个直接前驱和一个直接后继
例如:线性表,栈,队列
树形关系:一对多的关系,任何一个数据只能有一个直接前驱,但是可以有多个直接后继
例如:树,二叉树
图形关系(网状关系):多对多的关系,任何一个数据都有多个直接前驱和多个直接后继
例如:图
3.4存储关系
存储关系指的就是数据在内存中是如何存储的
顺序存储:
数据在内存中会开辟一段连续的内存空间进行存储,一般使用数组来存储数据
链式存储:
数据在内存中存储时不需要开辟一段连续的空间。
索引存储(一般不用)
哈希存储(一般不用)
注意:理论上,任何一种逻辑结构都可以用两种存储方式实现。
3.5 操作
增 删 改 查
四、顺序表(线性表的顺序存储)
4.1 概念
线性表:数据和数据之间的一对一的关系
顺序存储:需要在内存中开辟一段连续的内存空间存储数据,一般使用数组来存储数据,为了方便对数组进行操作,通常会定义一个变量来保存最后一个元素的下标
4.2 对顺序表的操作
4.2.1 创建一个空的顺序表
#include <stdio.h>
#include <stdlib.h>
//为了提高代码的拓展性,对数据类型取别名,方便对表中数据进行修改
typedef int DataType;
#define N 32
//定义一个结构体
typedef struct
{
DataType data[N];
int pos; //数组下标
}seqlist;
//顺序表的创建
seqlist *SeqlistCreate();
int main()
{
seqlist *st = SeqlistCreate();
return 0;
}
//顺序表的创建
seqlist *SeqlistCreate()
{
//在堆区申请空间
seqlist *st = (seqlist *)malloc(sizeof(seqlist));
//初始化,标识当前顺序表中没有元素
st->pos = -1;
//返回顺序表的首地址
return st;
}
4.2.2 判断顺讯表是否为满
//判断顺序表是否为满
int SeqlistFull(seqlist *st)
{
//方法1
#if 0
if(st->pos == N - 1)
{
return 1;
}
else
{
return 0;
}
#endif
//方法2
return st->pos == N - 1 ? 1 : 0;
}
4.2.3 插入数据
//插入数据
void SeqlistInsert(seqlist *st,DataType value)
{
//判断顺序表是否为满
if(SeqlistFull)
{
printf("顺序表为满,无法插入!\n");
return;
}
else
{
//保存最后一个元素变量pos自增
st->pos++;
//将数据插入到pos位置
st->data[st->pos] = value;
printf("插入成功!\n");
}
}
4.2.4 遍历顺序表
//遍历顺序表
void SeqlistPrint(seqlist *st)
{
int i;
for(i = 0;i <= st->pos;i++)
{
printf("%d",st->data[i]);
}
putchar(10);
}
4.2.5 判断顺序表是否为空
//判断顺序表是否为空
int SeqlistNull(seqlist *st)
{
//与判断是否为满一样有两种方法
return st->pos == -1 ? 1 : 0;
}
4.2.6 删除数据并返回删除的数据
//删除数据并返回删除的数据
DataType SeqlistDelete(seqlist *st)
{
if(SeqlistNull)
{
printf("顺序表为空,无法删除!\n");
return (DataType) - 1;
}
else
{
DataType value = st->data[st->pos];
st->pos--;
printf("删除成功!\n");
return value;
}
}
4.2.7 按照位置插入数据
//按照位置插入数据
void SeqlistInsertByPos(seqlist *st,int p,DataType value)
{
if(SeqlistFull(st))
{
printf("顺序表为满,无法插入!\n");
return;
}
//判断位置能否插入
else if (p < 0 || p > st->pos +1)
{
printf("位置有误,插入失败!\n");
return;
}
else
{
int i;
//如果插入最后一位,直接插入
if(p = st->pos + 1)
{
st->data[p] = value;
st->pos++;
}
else
{
//插入点后的数据后移一位
for ( i = st->pos; i > p; i--)
{
st->data[i + 1] = st->data[i];
}
//插入数据
st->data[p] = value;
st->pos++;
}
printf("插入成功!\n");
return;
}
}
4.2.8 按照位置删除数据,并返回删除的数据
//按照位置删除数据,并返回删除的数据
DataType SeqlistDeleteByPos(seqlist *st,int p)
{
if(SeqlistNull(st))
{
printf("顺序表为空,无法删除!\n");
return (DataType) - 1;
}
//判断位置能否删除
else if (p < 0 || p > st->pos +1)
{
printf("位置有误,删除失败!\n");
return (DataType) - 1;
}
else
{
//将要删除的数据保存在value中
DataType value = st->data[p];
int i;
//将删除位置位置以后的数据前移一位
for(i = p; i < st->pos;i++)
{
st->data[i] = st->data[i + 1];
}
st->pos--;
printf("删除成功!\n");
return value;
}
}
4.2.9 按照数据修改数据
//按照数据修改数据
void SeqlistUpdateByData(seqlist *st,DataType OldValue,DataType NewValue)
{
int i,flag = 0;
for(i = 0;i <= st->pos;i++)
{
if(st->data[i] == OldValue)
{
st->data[i] = NewValue;
flag = 1;
}
}
if(flag == 0)
{
printf("修改失败,数据%d不存在!",OldValue);
}
}
4.2.10 按照位置修改数据
//按照位置修改数据
void SeqlistUpdateByPos(seqlist *st,int p,DataType value)
{
if (p < 0 || p > st->pos +1)
{
printf("位置有误,修改失败!\n");
return;
}
else
{
st->data[p] = value;
printf("修改成功!\n");
}
}
4.2.11 按照数据查找位置
//按照数据查找位置
int SeqlistSearchByData(seqlist *st,DataType value)
{
int i;
for ( i = 0; i <= st->pos; i++)
{
if(st->data[i] == value)
{
printf("查找成功!\n");
return i;
}
}
printf("查找失败,数据%d不存在",value);
return -1;
}
4.2.12 按照位置查找数据
//按照位置查找数据
DataType SeqlistSearchByPos(seqlist *st,int p)
{
if (p < 0 || p > st->pos +1)
{
printf("位置有误,查找失败!\n");
return (DataType) -1;
}
else
{
printf("查找成功!\n");
return st->data[p];
}
}
练习:
1.删除重复数据
(将先出现的数据和后面的数据进行对比,如果有重复的将后面的数据删除)
s1: 1 2 2 2 1 1 3 4 2 4 5 4 1 -----> s1:1 2 3 4 5
//删除重复数据
void SeqlistDeleteRepeat(seqlist *st)
{
int i,j;
for(i = 0;i < st->pos;i++)
{
for(j = i + 1;j <= st->pos;j++)
{
if(st->data[i] == st->data[j])
{
SeqlistDeleteByPos(st,j);
j--;
}
}
}
}
2.合并表
(将s2里面与s1不一样的数据保存在s1的后面)
s1: 1 2 3 4 5
s2: 1 3 5 7 9
...
s1:1 2 3 4 5 7 9
//合并表
void SeqlistMerge(seqlist *s1,seqlist *s2)
{
int i;
for(i = 0;i < s2->pos;i++)
{
if(SeqlistSearchByPos(s1,s2->data[i]) == -1)
{
SeqlistInsert(s1,s2->data[i]);
}
}
}
五、顺序表的优缺点
优点:
操作简单,本质就是一个数组。
缺点:
需要开辟一段连续的内存空间,所以说如果存储的数据多就很不方便,在插入或删除数据的时候会出现内存数据成片移动的现象,效率非常低。