数据结构-线性表

线性表是最基本的数据结构。

基本概念

线性表(Linear List):由同类型数据元素构成有序序列的线性结构。

表中元素个数称为线性表的长度
线性表没有元素时称为空表
表起始位置为表头,表结束位置为表尾

抽象数据类型描述

类型名称:线性表
数据对象集:线性表是n个元素构成的有序序列(a1,a2,···,an)
操作集:线性表L属于List,整数i表示位置,元素X属于ElementType

  • List MakeEmpty():初始化一个空线性表L
  • ElementType FindKth(List L, Position K):根据位序K,返回相应元素
  • int Find(List L, ElementType X):在线性表L中查找X的第一次出现位置
  • void Insert(List L, ElementType X, Position i):在位序i前插入一个新元素X
  • void Delete(List L, Position i):删除指定位序i的元素
  • int Length(List L):返回线性表L的长度n

顺序存储实现

线性表的顺序存储实现利用数组的连续存储空间顺序存放线性表的个元素,也叫做顺序表

结构体定义
typedef int Position;
typedef struct LNode *List;
struct LNode{
	ElementType Data[MAXSIZE];      //用数组实现,MAXSIZE为最大存储容量
	Postion Last;				//末尾元素位置
};

访问下标为i的元素:L.Data[i]或PtrL->Data[i]
线性表的长度:L.Last+1或PtrL->L+1

初始化

初始化也就是建立空的顺序表

List MakeEmpty(){
	List L;
	L=(List)malloc(sizeof(struct LNode));		//内存分配
	L->Last=-1;        //没有元素时为-1	
	return L;
}
查找
Position Find(List L, ElementType X){
	Position i=0;
	while(i<=L->Last&&L->Data[i]!=X)
		i++;
	if(i>L->Last)
		return -1;		//没找到,返回-1
	else
		return i;		//找到,返回存储位置
}

查找成功的平均比较次数为(n+1)/2,平均时间性能为O(n)。

插入

要在第i个位置上插入一个值为X的元素,先从表尾开始到位序为i的元素依次往后移位,空出i,再将X插入。

void Insert(List L, ElementType X, Position i){
	Position j;
	if(L->Last==MAXSIZE-1){
		printf("表满");
		return;
	}
	if(i<0||i>L->Last+1){
		printf("位置不合法");
		return;
	}
	for(j=L->Last; j>=i; --j)
		L->Data[j+1]=L->Data[j];		//后移,第i个位置,数组下标为i-1
	L->Data[j]=X;		//插入
	L->Last++;		//Last依旧是表尾
}

插入的平均移动次数为n/2,平均时间性能为O(n)。

删除

要删除表的位序为i的元素,直接从i+1到表尾依次往前移位,覆盖前一个位置的元素。

void Delete(List L, Position i){
	Position j;
	if(i<0||i>PtrL->Last){
		printf("不存在%d号元素",i);
		return;
	}
	for(j=i; j<PtrL->Last; ++j)
		PtrL->Data[j]=PtrL->Data[j+1];		//前移,第i个位置,数组下标为i-1
	PtrL->Last--;
}

删除的平均移动次数为(n-1)/2,平均时间性能为O(n)。

链式存储实现

线性表的链式存储实现不要求逻辑上相邻的两个元素物理上也相邻,通过建立起数据元素之间的逻辑关系,也叫做链表
在链表中,每个结点除了要存储数据元素之外,还要存储一个指向其后继结点的指针。当然,结点可以有多个指针指向不同位置,而在此只讨论结点只有一个指针,即单链表。同时,结点有两个指针,一个指向前驱,一个指向后继,叫做双链表。

结构体定义
typedef struct LNode *PtrToLNode;
struct LNode{
	ElementType Data;		//数据元素
	PtrToLNode Next;		//指向后继的指针
};
typedef PtrToLNode Position;
typedef PtrToLNode List;
求表长度
int Length(List L){
	Position p=L;		//p指向链表头结点
	int j=0;
	while(p){
		p=p->Next;
		++j;		//当前p指向第j个结点
	}
	return j;
}

时间性能为O(n)。

查找

查找分为两种情况,一种是按序号查找,一种是按值查找。

Position FindKth(List L, int K){		//按序号查找,找第K个元素
	Position p=L;
	int i=1;
	while(p->Next&&i<K){
		p=p->Next;
		++i;
	}
	if(i==K)
		return p;		//找到第K个,返回指针
	else
		return NULL;		//未找到
}

Position Find(List L, ElementType X){		//按值查找,找元素X的位置
	Positon p=L;
	while(p&&p->Data!=X)
		p=p->Next;
	if(p)
		return p;
	else
		return NULL; 
}

查找的平均时间性能为O(n)。

插入

要在结点P之前插入新结点,先构造一个新结点,再找到P之前的结点,然后修改指针,插入新结点。

void Insert(List L, ElementType X, Position P){
	Position tmp, pre;
	for(pre=L; pre&&pre->Next!=P; pre=pre->Next)		//找到P的前一个结点
		;
	if(pre==NULL)
		printf("插入位置参数错误\n");
	else{
		tmp=(Position)malloc(sizeof(struct LNode));		//分配内存,构造结点
		tmp->Data=X;
		tmp->Next=P;
		pre->Next=tmp;
	}
}

平均查找次数为n/2,平均时间性能为O(n)。

删除

要删除结点P,先找到P之前的结点,然后修改指针,最后释放内存空间。

void Delete(List L, Position P){
	Position tmp, pre;
	for(pre=L; pre&&pre->Next!=P; pre=pre->Next)		//找到P的前一个结点
		;
	if(pre==NULL||P==NULL)
		printf("删除位置参数错误\n");
	else{
		tmp=P
		pre->Next=tmp->Next;		//删除P
		free(tmp);		//释放空间
	}
}

平均查找次数为n/2,平均时间性能为O(n)。