线性表
一、线性表的定义和基本操作
1.线性表的定义
线性结构的特点:在数据元素(节点)的非空有限集合中
(1)存在唯一的一个被称做“第一个”的数据元素(有头节点)
(2)存在唯一的一个被称做“最后一个”的数据元素(有尾节点)
(3)除第一个之外,集合中的每一个数据元素均只有一个前驱(在同一个线性结构下,中间节点或者尾结点的前一个节点是唯一的)
(4)除了最后一个之外,集合中每个数据元素均只有一个后推(在同一个线性结构下,中间节点或者头结点的后一个节点是唯一的)
但是循环链表是线性结构的
只要满足数据元素“一对一”的存储结构就是线性结构
2.约瑟夫环
约瑟夫环听说是西电经常的笔试考点我也不知道是不是,蛮学一下
约瑟夫环意思是有n数据元素组成一个循环线性表,从0开始数q个数,第q个数的数据元素被剔除,被剔除数据元素的下一个数据元素从头开始数q个数,直到剩下最后一个存活的数据元素
规律:Jq(n+1) = ( Jq(n) + q ) / (n+1)
具体解析可以看这个文章,写的蛮好的
https://blog.csdn.net/tingyun_say/article/details/52343897
3. 顺序存储
在计算机内容空间的存储地址是连续的两个相邻的数据元素仅相隔一个数据元素类型大小
4.链式存储
通过结构指针来表示一个数据元素,数据元素的地址可以不连续,但是头尾通过指针相连,进行数据存储。
静态链表
静态链表其实是一个顺序表,只是在顺序表的基础上增加了一个游标的标志为,用来判断下一个数据元素的数组下标。
在进行增删该查的时候,需要寻找到游标的所指示的上下节点,例如增加节点的时候,就是把上一个节点的游标改成当前存放新数据的数组下标,新增数据的游标为原数据的下一个节点数组下标。
初始化的时候可以把所有静态链表的游标赋值为一个特殊值,例如-2。
-1是静态链表的尾节点游标。
二、线性表的实现
线性表的实现,在讲之前要先讲一下以下几个函数。
//malloc在堆区开辟空间,长度为size,无类型地址返回,里面的数据要清空一下用memset
void *malloc(size_t size);
//calloc,在堆区开空间 nmemb:对象个数,size:对象大小,并且数据清空为0
void *calloc(size_t nmemb, size_t size);
//在开辟过的空间的地方后面重新开辟一个size大小的空间,如果后面的空间在被使用的话,重新找一块够大的空间开辟,并把原先的数据拷贝过去,原数据空间释放
void *realloc(void *ptr, size_t size);
//释放开辟的空间,必须要是malloc,calloc,realloc开辟的空间才能被释放
void free(void *ptr);
//memset str:要赋值数据的地址,c:赋值的值 n:赋值大小
void *memset(void *str, int c, size_t n) ;
1. 线性表初始化
顺序结构:
顺序结构的初始化要先开辟一个足够大的空间,空间满了可以用realloc添加新的空间
基本节点元素
//基本元素
typedef struct ElemType_T{
int id; //元素id
}ElemType;
typedef struct {
ElemType *elem; //存储空间基地址
int length; //当前长度
int listsize; //当前分配的存储容量
}SqList;
//初始化线性表
int InitList(SqList* sList){
sList->elem = (ElemType*)malloc(sizeof(ElemType) * LIST_INTI_SIZE); //申请内存空间
if (sList->elem == NULL) {
return ERROR;
}
sList->length = 0; //当前内存长度为0
sList->listsize = LIST_INTI_SIZE; //当前分配内存长度
memset(sList->elem, 0, sizeof(ElemType) * LIST_INTI_SIZE); //清空线性表
return OK;
}
链式结构:线性表初始化的话开辟一个头节点就可以了
节点元素
typedef struct List_T{
int id;
List* next;
List* up_next;
}List;
//初始化线性表
int Init_List_D(D_List** List){
*List = (D_List*)malloc(sizeof(D_List));
if (List == NULL) {
return ERROR;
}
memset(*List, 0, sizeof(D_List));
return OK;
}
2. 线性表添加数据
顺序表的就是根据SqList这个类里面的长度来找到对应位置添加数据,要添加对应位置的话,例如表内用n个数据,添加到第i位,i<=n。那么有6-i+1位的数据需要向后移动一位。
而链表就是根据下一个节点为空的性质找到尾节点,或者找到要添加的地方节点连接断开,连接上要插入的数据
3. 线性表删除数据
删除就和添加数据反过来了,不做赘述啦
4. 线性表修改数据
修改数据也还是找到对应位置,然后修改掉节点内的数据就可以啦
5. 线性表销毁
线性表销毁这个东西还是要说一下的
如果是顺序表的话可以用free来直接销毁
void DestroyList(SqList* List) //销毁线性表
{
if (List != NULL) {
free(List);
}
}
如果是链表的话需要用到遍历的方法找到一个节点保存下一个节点信息,然后再销毁,如果没保存的话会导致节点释放掉后,没法获取下一个节点信息,导致内存泄漏。
总结一下:
有点偷懒了,只是理解了一遍,没有好好的把全部的线性表的代码敲一遍,等后面有时间慢慢补吧,现在有点赶了,而且主要是自己之前做过一点点类似的项目大致的内容知道怎么搞,写了有点点超时的感觉,还是要巩固巩固,加油吧年轻人。