C language-big talk data structure: linear table
//
// Created by pengxiangzhou on 2021/1/24.
//
#include <form.h>
#ifndef C_DS_LINEAR_LIST_H
#define C_DS_LINEAR_LIST_H
#endif //C_DS_LINEAR_LIST_H
/*线性表-顺序存储结构
* 顺序存储结构的三个属性:数组data,存储位置为存储空间的位置;数组存储数据元素的最大值;线性表当前长度
* 数组的长度是存放线性表的存储空间的长度,存储分配后这个量一般不会变,线性表的长度等于线性表中数据元素的个数,线性表的长度<=数组的长度
* */
#define MAXIMIZE 20
typedef int ElemType;
typedef struct {
ElemType data[MAXIMIZE]; /*数组存储数据元素,最大值为MAXIMIZE*/
int length;
}SqList;
/*顺序表存储结构的插入与删除*/
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int Status;
/*获得元素操作
* Status是函数的类型,其值是函数结果状态代码,如OK等
* 初始条件:顺序线性表L已存在,1<= i <= ListLength(L)
* 操作结果:用e返回L中第i个数据元素的值
* */
Status Sequence_List_GetElem(SqList L, int i ,ElemType *e)
{
if(L.length ==0||i<1||i>L.length)
return ERROR;
*e = L.data[i-1];
return OK;
}
/*插入操作
*如果插入位置不合理,抛出异常;如果线性表长度大于等于数组长度,则抛出异常或动态增加容量;表长+1;
* 从最后一个元素开始向前遍历到第i个位置,分别将他们都向后移动一个位置;将要插入的元素填入位置i处;
* 这里的 "L->"代表"L."
* */
Status Sequence_ListInsert(SqList *L, int i, ElemType *e)
{
int k;
if (L->length==0) /*线性表为空*/
return ERROR;
if (i<1 || i >L->length) /*删除位置不正确*/
return ERROR;
*e=L->data[i-1];
if (i<L->length) /*如果删除不是最后位置*/
{
for (k=i;k<L->length;k++) /*将删除位置后继元素前移*/
L->data[k-1]=L->data[k];
}
L->length--;
return OK;
}
/*线性表-链式存储结构
* 每个数据元素除了存储本身的信息外,还要存储一个指示其直接后继的信息。
* 存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。指针域中存储的信息称作指针或链
* 数据域和指针域的两部分信息组成数据元素的存储映像,称为结点。
* 链表中的第一个结点的存储位置叫做头指针,头结点的数据域可不存储任何信息,也可以存储如线性表的长度等附加信息;线性链表的最后一个结点指针为空,用NULL表示
* */
/*p->data表示结点的数据域,p->next表示结点的i+1指针*/
typedef struct Node{
ElemType data;
struct Node *next; //结点由存放数据元素的数据域存放后继结点地址的指针域组成
}Node;
typedef struct Node *LinkList; /*定义LinkList*/
/* 获得元素操作
* 初始条件:顺序线性表L已存在,1<=i<=ListLength(L)
* 操作结果:用e返回L中第i个数据元素的值
* 缺点:必须从头开始找,直到第i个元素为止*/
Status Linked_structure_GetElem(LinkList L, int i ,ElemType *e) //?为什么不是LinkList *L
{
int j;
LinkList p; /*声明一结点p*/
p = L->next; /*让p指向链表L的第一个结点*/
j = 1; /*j为计数器*/
while (p&&j<i) /*p不为空或者计数器j还没有等于i时,循环继续*/
{
p = p->next; /*让p指向下一个结点*/
++j;
}
if (!p || j>i)
return ERROR;
*e = p->data;
return OK;
}
/*插入操作:在第i个数据中插入结点的算法思路
*声明一结点p指向链表第一个结点,初始化j从1开始
* 当j<i时,就遍历链表,让p的指针向后移动,不断指向下一结点,j累加1
* 若到链表末尾p为空,则说明第i个元素不存在
*
* */
/*初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/*操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1*/
#include <stdlib.h>
Status Linked_structure_ListInsert(LinkList *L, int i ,ElemType e)
{
int j;
LinkList p,s;
p = *L;
j = 1;
while (p&&j<i) /*寻找第i个结点*/
{
p = p->next;
++j;
}
if (!p || j>i)
return ERROR; /*第i个元素不存在*/
s = (LinkList) malloc(sizeof(Node)); /*生成新的结点,malloc在stdlib.h*/
s->data = e;
s->next = p->next;
p->next = s;
}
/*删除操作:将该结点的前继结点的指针绕过,指向后继结点,并释放该结点
* */
Status Linked_structure_ListDelete(LinkList *L, int i ,ElemType *e)
{
int j;
LinkList p,q;
p = *L;
j = 1;
while (p&&j<i) /*寻找第i个结点*/
{
p = p->next;
++j;
}
if (!(p->next)|| j>i)
return ERROR; /*第i个元素不存在*/
q = p->next;
p->next = q->next; /*将q的后继赋值给p的后继*/
*e = q->data; /*将q结点中的数据给e*/
free(q); /*让系统回收此结点,释放内存*/
return OK;
}
/*单链表的整表创建是个动态生成链表的过程,即从"空表"的初始状态起,其次建立各元素结点,并逐个插入链表
*随机产生n个元素的值,建立带表头结点的单链线性表L(头插法)
* */
#include <time.h>
void Linked_structure_CreateListHead(LinkList *L, int n )
{
LinkList p;
int i;
srand(time(0)); /*初始化随机数种子*/
*L = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL;
for (i = 0; i<n;i++)
{
p = (LinkList)malloc(sizeof(Node));
p->data = rand()%100+1; /*随机生成100以内的数字*/
p->next = (*L)->next;
(*L)->next = p;
}
}
void CreateListHead(LinkList *L, int n)
{
LinkList p;
int i;
srand(time(0));
*L = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL;
for (i = 0; i<n;i++)
{
p = (LinkList)malloc(sizeof(Node));
p->data=rand()%100+1;
p->next=(*L)->next;
(*L)->next=p;
}
}
void CreatListTail(LinkList *L,int n)
{
LinkList p,r;
int i;
srand(time(0));
*L = (LinkList)malloc(sizeof(Node)); /*L是指整个单链表*/
r = *L; /*r为指向尾部的结点,r会随着循环增长为一个多结点的链表*/
for (i=0;i<n;i++)
{
p = (Node *)malloc(sizeof(Node));
p->data = rand()%100+1;
r->next = p;
r=p; /*新结点是尾结点,记为r*/
}
r->next = NULL; /*将尾结点的指针域置空*/
}
Status ClearList(LinkList *L)
{
LinkList p,q;
p = (*L)->next; /*p指向第一个结点*/
while (p) /*没到表尾*/
{
q = p->next; /*当前结点被释放后,q用于记录下一个结点的信息*/
free(p);
p = q;
}
(*L)->next = NULL; /*头结点指针域为空*/
return OK;
}
/*静态链表;使用数组代替指针,来描述单链表
* 数组的元素由两个数据域组成,data和cur;数组的每个下表都对应一个data(数据域,存放数据元素)和一个cur(相当于单链表的next指针,存放该元素的后继在数组中的下标)
* */
/*线性表的静态链表存储结构*/
#define MAXSIZE 1000
typedef struct
{
ElemType data;
int cur;
} Component,StaticLinkList[MAXSIZE];
/*将一维数组space中各分量链成一备用链表,space[0].cur为头指针,"0"表示空指针*/
Status InitList(StaticLinkList space)
{
int i;
for (i = 0 ; i < MAXIMIZE; i ++)
space[i].cur = i +1;
space[MAXIMIZE-1].cur = 0; /*目前静态链表为空,最后一个元素的cur为0*/
return OK;
}
/* 静态链表的插入操作
* 需要解决的问题:静态模拟动态链表结构的存储空间的分配,需要时申请,无用时释放
* 在动态链表中,结点的申请和释放分别借用malloc()和free()来实现,静态链表不存在该函数,需要自行实现
* 解决方法:将所有未被使用过的及已被删除的分量用游标链成一个备用的链表,每当进行插入时,从备用链表上取得第一个结点作为待插入的新结点
* */
/*若备用空间链表非空,则返回分配的结点下标,否则返回0
*数组第一个元素的cur用来存放备用链表第一个结点的下标
* */
int ListLength(StaticLinkList L)
{
int j = 0;
int i = L[MAXIMIZE-1].cur;
while (i)
{
i = L[i].cur;
j++;
}
return j;
}
int Malloc_SLL(StaticLinkList space)
{
int i = space[0].cur; /*返回第一个备用空闲的下标*/
if (space[0].cur)
space[0].cur = space[i].cur; /*拿出下一个分量用来做备用*/
return i; /*返回数组头元素的cur存的第一个空闲的下标*/
}
/*?在L中第i个元素之前插入新的数据元素e*/
Status ListInsert(StaticLinkList L, int i, ElemType e)
{
int j, k , l;
k = MAXIMIZE - 1; /*k是最后一个元素的下标*/
if (i<1||i> ListLength(L)+1)
return ERROR;
j = Malloc_SLL(L); /*获得空闲分量的下标*/
if (j)
{
L[j].data=e; /*将数据赋值给此分量的data*/
for(l=1;l<=i-1;l++) /*找到第i个元素之前的位置*/
k=L[k].cur;
L[j].cur = L[k].cur; /*把第i个元素之前的cur赋值给新元素的cur*/
L[k].cur = j; /*把新元素的下标赋值给第i个元素之前元素的cur*/
return OK;
}
return ERROR;
}
/*?删除在L中第i个数据元素e*/
void Free_SSL(StaticLinkList space, int k)
{
space[k].cur = space[0].cur; /*把第一个元素cur值赋给要删除的分量cur*/
space[0].cur = k; /*把要删除的分量下标赋值给第一个元素的cur*/
}
Status ListDelete(StaticLinkList L,int i )
{
int j,k;
if (i>ListLength(L)+1||i<1)
return ERROR;
k = MAXIMIZE - 1;
for (j=1;j<=i-1;j++)
k = L[k].cur;
j = L[k].cur;
L[k].cur = L[j].cur;
Free_SSL(L,j);
return OK;
}
/*循环链表:将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表形成一个环
* 循环链表和单链表的主要差异在于循环的判断条件:单链表判断p->next是否为空,循环链表判断p->next是否等于头结点*/
/*双向链表:在单链表的每个结点中,再设置一个指向其前驱结点的指针域,双向链表中的结点都有两个指针域,一个指向直接后继,一个指向直接前驱
* 优点:可以反向遍历查找等数据结构,但是在插入和删除时,需要更改两个指针变量
* */
/*线性表的双向链表存储结构*/
typedef struct DulNode
{
ElemType data;
struct DulNode *prior; /*直接前驱指针*/
struct DulNode *next; /*直接后继指针*/
}DulNode,*DuLinkList;