线性表的元素的个数(n>=0)定义为长度,n=0为空表
抽象数据类型(ADT):是指一个数据模型及定义在该模型上的一组操作(类似于类)
数据类型:是指一组性质相同的值的集合及定义在此集合上的一些操作的总称,浮点型,字符型
标准格式:
ADT 抽象数据类型名
Data
数据元素之间逻辑关系的定义
Operation
操作
endADT
ADT线性表(List)
Data
线性表的数据对象集合为{a1,a2,...,an},每个元素的类型均为DataType。其中,除第一个
元素a1外,每个元素有且只有一个直接前驱元素,除了最后一个元素an外,每一个元素有且
只有一个直接后继元素。数据元素之间的关系是一对一的关系
Operation
InitList(*L):初始化操作,建立一个空的线性表L
ListEmpty(L):判断线性表是否为空表,若为空,返回true,否则返回false
ClearList(*L):将线性表清空
GetElem(L,i,*e):将线性表L中的第i个位置元素值返回给e
LocateElem(L,e):在线性表L中查找与给定e相等的元素,如果查找成功,返回该元素在表中
序号表示成功;否则返回0表示失败
ListInsert(*L,i,e):在线性表L中的第i个位置插入新元素e
ListDelete(*L,i,*e):删除线性表L中第i个位置元素,并用e返回其值
ListLength(L):返回线性表L的元素个数
endADT
线性表的顺序存储结构:
#define ok 1
#define error 0
#define true 1
#define false 0
#define maxsize 20
typedef int elemtype;
typedef struct
{
elemtype data[maxsize];
int length;
}SqList;
三个属性:
-存储空间的起始位置,数组data
-线性表的最大存储容量:数组的长度maxsize
-数组表的当前长度:length
Status GetElem(SqList L,int i,elemtype *e)
//getElem具体操作,即将线性表L中的第i个位置元素值返回
{
if(L.length==0||i<1||i>L.length)
{
return error;
}
*e = L.data[i-1];
return ok;
}
status ListInsert(SqList *L,int i,elemtype e)
//在线性表L中的第i个位置插入新元素e
思路:
如果插入位置不合理,抛出异常
如果线性表长度大于扽股数组长度,抛出异常或动态增加数组容量
从最后一个元素开始遍历到第i个位置,分别将他们向后移动一个位置
线性表长度加1
{
if(L->length==maxsize)
return reeor;
if(i<1||i>L->length+1)
return error;
if(i<=L->length)
{
for(k=L->length-1;k>=i-1;k--)
{
L->data[k+1] = L->data[k];
}
}
L->data[i-1] = e;
L->length++;
}
status ListDelete(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->dat[k];
}
L->length--;
return ok;
}
O((n-1)/2) = O(n)插入删除
存,读数据O(1)
线性表的链式存储结构:
头节点的数据域不存储任何信息
头指针:头指针是指链表指向第一个节点的指针,若链表有头节点,则是指向头节点的指针
头指针具有标识作用,所以常用头指针冠以链表的名字
无论链表是否为空,头指针均不为空
头节点是为了操作的统一和方便而设立的放在第一个元素的结点之前,其数据域一般无意义
头节点不一定是链表的必要元素
typedef struct node
{
elemtype data;
struct node *next;
}node;
typedef struct node* LinkList;
status GetElem(Linklist L,int i,Elemtype *e)
//声明一个结点p指向俩表第一个节点,初始化j从1开始
{
int j;
Linklist p;
p=L->next;
j=1;
while(p&&j<i)
{
p=p->next;
++j;
}
if(!p||j>i)
return error;
*e = p->data;
return ok;
}最坏O(n)
//插入
status ListInsert(Linklist *L,int i,elemtype e)
{
int j;
Linklist p,s;
p=*L;
j=1;
while(p&&j<i)
{
p=p->next;
j++;
}
if(!p||j>i)
return error;
s=(Linklist)malloc(sizeof(node));
s->data=e;
s->next = p->next;
p->next=s;
return ok;
}
//假设元素a2的结点为q,要实现结点q删除点链表操作,其实就是将它的前继结点的指针绕过指向后集结点即可
status ListDelete(Linklist *L,int i,elemtype *e)
{
int j;
LinkList p,q;
p=*L;
j=1;
while(p->next&&j<i)
{
p=p->next;
++j;
}
if(!(p->next)||j>i)
return error;
q=p->next;
p->next = q->next;
*e = q->next;
free(q)
return ok;
}
单链表的整表创建
头插法:从一个空表开始,将新节点插入到当前链表的表头head元素后
--新节点的next指向头节点之后
--然后让表头的next指向新节点
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 CreateListTail(LinkList *L,int n)
{
LinkList p,r;
int i;
srand(time(0));
*L = (LinkList)malloc(sizeof(Node));
r = *L;
for(int i=0;i<n;i++)
{
p = (Node*)malloc(sizeof(Node));
p->data = rand()%100+1;
r->next=p;
r=p;//以前的p现在既是p也是r
}
r->next = NULL;
}
单链表的整表删除
--声明结点p,q;
--将第一个节点赋值给p,下一个赋值给q
status ClearList(LinkList *L)
{
LinkList p,q;
p=(*L)->next;
while(p)
{
q=p->next;
free(p);
p=q;
}
(*L)->next = NULL;
return ok;
}
静态链表:
用数组描述的链表叫做静态链表
#define maxsize 1000
typedef struct
{
elemtype data;//数据
int cur;//游标
}Component,StaticLinkList[maxsize];
游标
数据
下标
游标指向下标
初始化数组:
status InitList(StaticLinkList space)
{
int i;
for(i= 0 ;i<maxsize-1;i++)
space[i].cur=i+1;
space[maxsize-1].cur=0;
return ok;
}
把未使用的数组元素称为备用数组
数组的最后一个元素,即maxszie-1的cur则存放第一个由数值的元素的下标,则相当于单链表的头节点的作用