1.什么是数据结构
数据结构是由“数据”和“结构”两词组合而来。
什么是数据?常见的数值1、2、3、4.....、教务系统里保存的用户信息(姓名、性别、年龄、学历等等)、网页里肉眼可以看到的信息(文字、图片、视频等等),这些都是数据。
什么是结构?
当我们想要使用大量使用同一类型的数据时,通过手动定义大量的独立的变量对于程序来说,可读性非常差,我们可以借助数组这样的数据结构将大量的数据组织在一起,结构也可以理解为组织数据的方式。
想要找到草原上名叫“咩咩”的羊很难,但是从羊圈里找到1号羊就很简单,羊圈这样的结构有效将
羊群组织起来。
概念:数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系
的数据元素的集合。数据结构反映数据的内部构成,即数据由那部分构成,以什么方式构成,以及数据元素之间呈现的结构。
总结:
1)能够存储数据(如顺序表、链表等结构)
2)存储的数据能够方便查找
2、为什么需要数据结构?
如图中所示,不借助排队的方式来管理客户,会导致客户就餐感受差、等餐时间长、餐厅营业混乱等情况。同理,程序中如果不对数据进行管理,可能会导致数据丢失、操作数据困难、野指针等情况。通过数据结构,能够有效将数据组织和管理在一起。按照我们的方式任意对数据进行增删改查等操作。
最基础的数据结构:数组。
比如,我创建了数组 arr[5] = { 1,2, 3, 4 ,5}, 我想修改某一个数据,插入或删除一个数据,会非常的麻烦甚至会影响效率等,所以最基础的数据结构能够提供的操作已经不能完全满足复杂算法实现(增删查改等)。
2.顺序表
1 顺序表的概念及结构
· 顺序表是线性表的一种
线性表(linear list)是n个具有相同特性的数据元素的有限序列(具有部分相同特性的一类数据结构的集合)。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...
特性:线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
物理结构:不一定连续(实际内存储存)
逻辑结构:连续的(肉眼所见,或心之所想)
例:蔬菜分为绿叶类、瓜类、菌菇类。
2 顺序表分类
• 顺序表和数组的区别
顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接口
• 顺序表分类
◦静态顺序表
概念:使用定长数组存储元素
struct SeqList
{
int arr[100];//定长数组,一开始就知道内存
int size;//记录顺序表当前有效的数据个数
};
数组大小给小了 ,空间不够用(例如用户信息丢失等)
数组大小给大了,空间浪费
◦ 动态顺序表
struct SeqList
{
int* arr;//动态数组
int size;//记录有效的数据个数
int capacity;//记录申请到的空间大小
};
可动态增容:原来有100个内存,现在增到了101,102等有目的的个数,减少了定长数组的问题。
3、动态顺序表的实现
#define INIT_CAPACITY 4
typedef int SLDataType;
// 动态顺序表 -- 按需申请
typedef struct SeqList
{
SLDataType* a;
int size; // 有效数据个数
int capacity; // 空间容量
}SL;
//初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);
//扩容
void SLCheckCapacity(SL* ps);
//头部插入删除 / 尾部插入删除
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
//指定位置之前插入/删除数据
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
int SLFind(SL* ps, SLDataType x);
SeqList.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//定义顺序表的结构
静态
//#define N 100
//struct SeqList
//{
// int arr[N];
// int size;//有效数据个数
//};
typedef int SLDataType;//SLDataType 是数据类型,这里是 int
//动态
typedef struct SeqList
{
SLDataType* arr;
int size;//有效数据个数
int capacity;//空间大小
}SL;//SL 作为他的名字方便使用
//顺序表初始化
void SLInit(SL* ps);
//顺序表销毁
void SLDestroy(SL* ps);
//头部插入删除 / 尾部插入删除
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);
SeqList.c
#include "SeqList.h"
void SLInit(SL* ps)
{
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
//顺序表的销毁
void SLDestroy(SL* ps)
{
if (ps->arr)
{
free(ps->arr);
}
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
void SLCheckCapacity(SL* ps)
{
//插入数据之前先看空间够不够
if (ps->capacity == ps->size)
{//增容一般是成倍增加,一般是2或3倍
//申请空间
int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;//三目表达式
SLDataType* tmp = (SLDataType*)raelloc(ps->arr, newCapacity * sizeof(SLDataType));
if (tmp == NULL)
{
perror("realloc fail!");
exit(1);//直接退出程序不再执行
}
//申请成功
ps->arr = tmp;
ps->capacity = newCapacity;
}//若要频繁地增容,则会造成程序性能低下,效率降低
}
//尾差
void SLPushBack(SL* ps, SLDataType x)
{
assert(ps);//等价 assert(ps != NULL)
/*ps->arr[ps->size] = x;
++ps->size;*/
SLCheckCapacity(ps);
ps->arr[ps->size++] = x;
}
//头差
void SLPushFront(SL* ps, SLDataType x)
{
SLCheckCapacity(ps);
//先让顺序表中已有的数据整体后移1位
for (int i = ps->size; i > 0;i--)
{
assert(ps);
ps->arr[i] = ps->arr[i - 1];//把数组前一个数据后移一个
}
ps->arr[0] = x;
ps->size++;
}
//打印
void SLPrint(SL s)
{
for (int i = 0; i < s.size; i++)
{
printf("%d", s.arr[i]);
}
printf("\n");
}
//尾删
void SLPopBack(SL* ps)
{
assert(ps);
assert(ps->size);
--ps->size;
}
//头删
void SLPopFront(SL* ps)
{
assert(ps);
assert(ps->size);
//整体往前挪动一位
for (int i = 0; i < size - 1; i++)
{
ps->arr[i] = ps->arr[i + 1];arr[size - 2] = arr[size - 1]
}
ps->size--;
}
test.c
#include "SeqList.h"
void SLTest01()
{
SL s1;
SLInit(&s1);
//增删查改操作
//测试尾插
SLPushBack(&s1, 1);
SLPushBack(&s1, 2);
SLPushBack(&s1, 3);
SLPushBack(&s1, 4);
SLPrint(s1);
SLPushFront(&s1, 5);
SLPushFront(&s1, 6);
SLPushFront(&s1, 7);
SLPushFront(&s1, 8);
SLPrint(s1);
//尾删
SLPopBack(&s1);
SLPrint(s1);//1 2 3
SLPopBack(&s1);
SLPrint(s1);//1 2
//头删
SLPopFrint(&s1);
SLPrint(s1);//2 3 4
SLPopFrint(&s1);
SLPrint(s1);//3 4
SLDestroy(&s1);
}
int main()
{
SLTest01;
return 0;
}