什么是数据
描述客观事物的符号,是计算机中可以操作的对象,
是能被计算机识别,并输入给计算机处理的符号集合。注意:
# 数据有两个特点:
1. 可以输入给计算机
2. 能够被计算机程序处理# 数据不仅仅包括整型、实型等数值类型, 还包括字符及声音、图像、视频等非数值类型。
数据元素:
组成数据的、有一定意义的基本单元、
在计算机中通常作为整体处理,也被称为记录。数据项:
一个数据元素可以由若干个数据项组成# 数据项是数据不可分割的最小单位
4.数据对象:
性质相同的数据元素的集合,是数据的子集
5.数据结构:
数据元素 + 特定关系 = 数据结构
数据结构是相互之间存在一种或多种特定关系的数据元素的集合
现实世界中, 不同的数据元素之间不是独立的,而是存在特定关系, 我们称这些关系为结构
逻辑结构与物理结构
一、 逻辑结构
1. 集合结构
1. 集合结构中的数据元素同属一个集合
2. 数据元素相互之间没有其他关系
2. 线性结构
1. 数据元素之间是一对一的关系
3. 树形结构
1. 数据元素之间存在一种一对多的层次关系
4. 图形结构
1. 数据元素之间是多对多的关系
二、 物理结构
定义: 又叫存储结构,是指数据的逻辑结构在计算机中的存储形式
1. 顺序存储结构
* 把数据元素存储在地址连续的内存单元里
* 数据间的逻辑关系与物理关系一直
2. 链式存储结构
* 把数据元素存放在任意的存储单元里
抽象数据类型
数据类型:
计算机中,内存空间是有限的,不同类型的数据分配的内存空间大小不同。
数据类型是指一组性质相同的值的集合及定义在此集合上的一些操作的总称。
在C语言中,按照取值的不同,数据类型分为两类:
1. 原子型:
不可以再分解的基本类型,包括整型,实型,字符型等。
2. 结构型:
由若干个类型组合而成,是可以再分解的。例如:整型数组是由若干个整型数据组成的。
抽象数据类型(ADT):
是对已有的数据类型进行抽象。
抽象数据类型是指一个数据模型及定义在该模型上的一组操作。
一种思考方式,隐藏了实现细节。概念层。
1. 把实际生活中的问题分解为多个规模小且容易实现处理的问题。
2. 建立一个计算机能处理的数据模型
3. 把每个功能模块的实现细节作为一个独立单元,使具体实现过程隐藏起来。
*** 抽象数据类型的标准格式:
ADT 抽象数据类型名
Data
数据元素之间逻辑关系的定义
Operation
操作1
初始条件
操作结果描述
操作2
....
操作n
....
endADT
设计和实现是分开
2.1线性表抽象数据类型
线性表:
定义:零个或多个元素的有限序列
一个数据元素包含多个数据项。
线性表的特点:
1. 它是一个序列
- 数据元素之间有序的
- 数据元素之间是一对一的关系
2. 有限性
- 线性表的数据元素个数是有限的。
零个数据元素的有限序列又被称为空表。
线性表的常见操作:
- 创建和初始化
- 查找
- 插入
- 删除
- 清空
即为:增、删、改、查
ADT 线性表(SequenceList)
Data
1. 线性表数据元素是一个集合{a_1, a_2, ... a_n},数据元素的类型DataType(int, char, 自定义)
2. 除了第一个元素a_1外, 每个元素有且只有一个直接的前驱元素
3. 除了最后一个元素a_n外, 每个元素有且只有一个直接的后继元素
4. 每个数据元素之间的关系是一对一的关系
Operation
- InitList(*List) 初始化线性表:创建一个空的线性表List
- InsertElement(*List, index, elem) 在线性表List的index下标处插入元素elem
- DeleteElement(*List,index,*elem) 删除线性表List中第i个元素,并返回删除元素的指针e
- GetLength(*List)
- IsEmpty(*List)
- GetElement(*List, index, *elem)
顺序存储结构的线性表 – 顺序表
线性表:
线性表的顺序存储结构,指的是用一段地址连续的存储单元一次存储线性表的数据元素。
# 描述线性表的顺序存储结构需要三个属性:
1. 我们需要定义线性表的最大存储空间
# define MAX SIZE 255
2. 线性表里需要有统一类型的元素集合
# typedef int ElemType;
# typedef struct {
int id;
char * name;
}ElementType;
3. 定义线性表结构
# typedef struct{
ElementType datas[MAX SIZE];
int length;
};
- 存储空间的起始位置: 数组datas的存储位置
- 线性表的最大存储容量:数组长度MAX_SIZE
- 线性表的当前长度:length
# 地址计算方法
第 1 个元素的内存地址 = 数组的内存长度 + 第 1 个元素的下标 0
*(datas + 0)
*(datas + 1)
*(datas + n-1)
position 位置,从1开始
index 下标,从0开始
顺序存储结构的插入与删除
# 顺序表插入数据元素
将数据元素a插入到顺序表(a1, a2, ... ,ai,ai+1, ... ,an)下标为i的位置
# 下标为i及下标为i以后的所有数据元素后移
## 注意:
除非 i=n+1, 否则必须移动数据元素的位置类适应逻辑结构的改变
## 注意:
1. 插入数据后的顺序表长度变为n+1
2. 插入元素后,最后一个元素的下标变为n
3. C语言数组实现时,顺序表长度不能超过它的最大长度
代码实现顺序表的插入
DataElement.h
//
// Created by lis on 18-8-25.
//
#ifndef STRUCT_SEQLIST_INSERT_DATAELEMENT_H
#define STRUCT_SEQLIST_INSERT_DATAELEMENT_H
/**
* 数据结构第二章案例
* 用来定义数据元素
*
*/
#define MAX_SIZE 255
// 1. 定义数据元素
//typedef int ElementType;
typedef struct {
int id;
char * name;
}ElementType;
// 2. 定义顺序表结构
typedef struct {
ElementType datas[MAX_SIZE]; //顺序表中的元素集合
int length; //当前顺序表中的元素个数
}SeqList;
#endif //STRUCT_SEQLIST_INSERT_DATAELEMENT_H
SequenceList.h
//
// Created by lis on 18-8-25.
//
#ifndef STRUCT_SEQLIST_INSERT_SEQUENCELIST_H
#define STRUCT_SEQLIST_INSERT_SEQUENCELIST_H
/**
* 数据结构第二章案例
* 定义顺序表
*/
#include <stdio.h>
#include <stdlib.h>
#include "DataElement.h"
/**
* 初始化顺序表
* @param seqList 要初始化的顺序表
* @param elementArray 初始化时要添加的元素内容数组
* @param length 初始化时添加的元素个数
*/
void InitList(SeqList *seqList, ElementType *elementArray, int length);
/**
* 向顺序表中的 index 下标处插入某个元素
* @param seqList
* @param index 要插入的下标
* @param element 要插入的元素
*/
void InsertElement(SeqList *seqList, int index, ElementType element);
void PrintList(SeqList * seqList);
#endif //STRUCT_SEQLIST_INSERT_SEQUENCELIST_H
代码实现顺序表的删除元素
/**
* 删除顺序表中指定下标的数据元素
* @param seqList 要操作的顺序表
* @param index 要删除的下标
* @return 返回删除的元素, 如果删除失败, 返回NULL
*/
ElementType * DeleteElement(SeqList * seqList, int index)
{
if(index<0 || index>MAX_SIZE)
{
printf("下标越界, 无法删除指定下标的元素");
return NULL;
}
// 1. 找到要删除的元素,并保存起来以便返回(保存的是已删除元素的副本!!!)
ElementType * delElement = (ElementType *)malloc(sizeof(ElementType));
// 单独定义并调用查找函数,返回要删除元素的指针
*delElement = *GetElement(seqList, index);
// 2. 从指定位置删除, 后面元素赋值给前面一个元素
for(int i=index; i<seqList->length-1; i++)
{
seqList->datas[i] = seqList->datas[i+1];
}
// 3. 顺序表的总长度-1
seqList->length--;
return delElement; //建议使用完毕后进行free, 否则会造成内存泄露
}
/**
* 返回顺序表中指定下标的元素
* @param seqList 要操作的顺序表
* @param index 要返回的元素下标
* @return 返回指定下标的元素,如果查找失败, 返回NULL
*/
ElementType * GetElement(SeqList * seqList, int index)
{
if(index<0 || index>MAX_SIZE)
{
printf("下标越界, 无法找到指定下标的元素");
return NULL;
}
ElementType * element;
element = &seqList->datas[index];
}
线性表顺序存储结构的优点
1. 无须为表示表中元素之间的逻辑关系而增加额外的存储空间
2. 可以快速地存取表任意位置的元素
线性表顺序存储结构的缺点
1. 插入和删除操作需要移动大量的元素
2. 当线性表长度变化较大时, 难以确定存储空间的容量
3. 造成空间的“碎片”
链表
####链式存储结构的线性表 -- 链表
基本概念:
1. 结点包括数据域和指针域
2. 链表是由n个结点链结成, 第一个结点的存储位置叫做头指针, 最后一个结点的指针为“空”
typedef struct Monster{
int id;
char * name;
struct Monster * next; // 指向下个结点的指针
}
void test()
{
Monster monster_one = {1, "是莱克"};
Monster monster_two = {2, "格斯拉"};
Monster monster_three = {3, "西医长者"};
Monster monster_four = {4, "远古墨香"};
Monster monster_five = {5, "那时勇士"};
// monster就是头指针
monster_one.next = &monster_two;
monster_two.next = &monster_three;
monster_three.next = &monster_four;
monster_four.next = &monster_five;
monster_five.next = NULL;
}
相对于顺序表的优点
1. 不用定义时规定长度
2. 存储的元素个数不受限制
3. 插入和删除元素时, 不用移动其他元素
链表的头指针和头结点
基本概念:
- 头指针: 链表中第一个结点的存储位置
- 头结点: 在单链表中的第一个结点前附设的一个结点
单链表的查找与插入
基本概念:
- 链表的每一个结点中只包含一个指针域 ---> 单链表
单链表的读取数据元素
- 获取第i个结点的数据元素
1. 声明一个结点指针p指向链表第一个结点a_1, 初始化j从1开始;
2. 当j<i时, 遍历链表, 让p的指针向后移动, 不断指向下一个结点, j累加1;
3. 若当链表末尾p为空, 则说明第i个元素不存在; 否则查找成功, 返回结点p的数据。
单链表的插入数据元素:
在第i个结点之后插入数据元素
1. 创建一个空结点, 分配内存空间, 设置元素数据
2. 获取第i个结点, 设置新结点的后继结点为该结点的后继结点
3. 设置第i个结点的后继结点为新的结点