数据结构 第二章 线性表

线性结构的特点:
(1)存在唯一的一个被称做“第一个”的数据元素;
(2)存在唯一的一个被叫做“最后一个”的数据元素;
(3)除第一个之外,集合中的每个数据元素均只有一个前驱;
(4)除最后一个之外,集合中每个数据元素均只有一个后驱;

2.1线性表的类型定义

ADT List{
	数据对象:
	数据关系:
	基本操作:
	InitLisst(&L);
	DestroyList(&L);
	ClearList(&L);
	ListEmpty(L);
	ListLength(L);
	GetElem(L,i,&e);
	LocateElem(L,e,compare());
	PriorElem(L,cur_e,&pre_e);
	NextElem(L,cur_e,&next_e);
	ListInsert(&L,i,e);
	ListDelet(&L,i,e);
	ListTraverse(L,visit());
}ADT List
/*算法2.1两个线性表的合并*/
void union(List &La,List Lb)
{
	la_len=ListLength(La);
	lb_len=ListLength(Lb);
	for(i=1;i<lb_len;i++)
	{
		GetElem(Lb,i,e);
		if(!LocateElem(La,e,equal))
			ListInsert(La,++La_len,e);
	}
}
/*算法2.2将两个非递减序列线性链表合并成非递减线性链表*/
void MergeList(List La,List Lb,List &Lc)
{
	InitList(Lc);
	i=j=1;k=0;
	La_len=ListLength(La);
	Lb_len=ListLength(Lb);
	while((i<=La.len)&&(j<=Lb_len))
	{
		GetElem(La,i,ai);
		GetElem(Lb,j,bj);
		if(ai<=bj)
		{
			ListInsert(Lc,++k,ai);
			++i;
		}else
		{
			ListInsert(Lc,++k,bj);
			++j;
		}
	}

	while(i<=La_len)
	{
		GetElem(La,i++,ai);
		ListInert(Lc,++k,ai);
	}
	while(j<=Lb_len)
	{
		GetElem(Lb,j++,bi);
		ListInsert(Lc,++k,bj);
	}
}

2.3线性表的顺序表示和实现

/*线性表的动态分配顺序存储结构*/
#define LIST_INIT_SIZE	100
#define LISTINCREMENT	10
typedef struct
{
	ElemType *elem;//存储空间基址
	int length;
	int listsize;//当前分配存储容量
}SqList;
/*算法2.3顺序表的初始化*/
Status InitList_Sq(SqList &L)
{
	L.elem=(ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));
	if(!L.elem)
		eixt(OVERFLOW);	
	L.length=0;
	L.listsize=LIST_INIT_SIZE;
	return OK;
}

!](https://img-blog.csdnimg.cn/20190325210801160.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FuYWxvZ0VsZWN0cm9uaWM=,size_16,color_FFFFFF,t_70)

//算法2.4线性表的插入操作
Status ListInsert_Sq(SqList &L,int i,ElemType)
{
	if(i<1||i>L.length+1)


		return ERROR;
	if(L.length>=L.listsize)
	{
		newbase=(ElemType *)realloc(L.elem,L.(listsize+LISTINREMENT)*sizeof(ElemType));
		if(!newbase)exit(OVERFLOW);
		L.elem=newbase;
		L.listsize+=LISTINCREMENT;
	}
	q=&(L.elem[i-1]);
	for(p=&(L.elem[L.length-1]);p>=q;--p)
		*(p+1)=*p;
		*q=e;
		++L.length;
		return OK;
}
//算法2.5线性表的第i个元素删除操作
Status ListDelete_Sq(SqList &L,int i,ElemType &e)
{
	if((i<1||(i>L.length))
		return ERROR;
	p=&(L.elem[i-1]);
	e=*p;
	q=L.elem+L.length-1;
	for(++p;p<=q;++p)
		*(p-1)=*p;
	--L.Length;
	return OK;
}
int LocateElem_Sq(SqList L,ElemType e,Status(*compare)(ElemType,ElemType))
{
	//在顺序表L中查找第1个值与e满足compare()元素的位序
	//若找到,则返回其在L中的位序,否则返回0
	i=1;		//i的初始值为第一个元素的位序
	p=L.elem;	//p的初值为第1个元素的为序
	while(i<=L.length&&!(*compare)(*p++,e)) ++1;
	if(i<=L.length)	return i;
	else return 0;
}//LocateElem_Sq
void MergeList_Sq(SqList La,SqList Lb,SqList &Lc)
{
	//已知顺序线性表La和Lb的元素按非递减排序
	//归并La和Lb得到新的顺序线性表Lc,Lc的元素也按值非递减排列
	pa=La.elem;pb=Lb.elem;
	Lc.listsize=Lc.length=La.length+Lb.length;
	pc=Lc.elem=(ElemType*)malloc(Lc.listsize*sizeof(ElemType));
	if(!Lc.elem)exit(OVERFLOW);
	pa_last=La.elem+La.length-1;
	pb_last=Lb.elem+Lb.length-1;
	while(pa<=pa_last&&pb<=pb_last)
	{
		if(*pa<=*pb)  *pc++=*pa++;
		else *pc++=*pb++;
	}
	while(pa<=pa_last) *pc++=*pa++;	//插入La的剩余元素
	while(pb<=pb_last) *pc++=*pb++; //插入Lb的剩余元素
}

2.3线性链表的表示和实现

在这里插入图片描述
在这里插入图片描述

//线性链表的单链表存储结构
typedef struct LNode
{
	ElemType	data;
	struct LNode	*next;
}LNode,*LinkList;
//单链表是非随机存储的数据结构
//算法2.8
Status GetElem_L(LinkList L,int i,ElemType &e)
{
	//L为带头结点的单链表的头指针
	//当第i个元素存在时,其值赋给e并返回OK,否则返回false
	p=L->next; j=1;//初始化,p指向第一个节点,j为计数器
	while(p&&j<i)
	{
		p=p->next; ++j;
	}
	if(!p||j>j) return EROOR;//第i个元素不存在
	e=p->data;
	return OK;
}

在这里插入图片描述

/*除了函数的参数需要说明类型外,算法中使用的辅助变量可以不作变量说明
,必要时对其作用给予注释。一般而言,a,b,c,d,e等用作数据元素名,i,j,k,l,m,n
等用作整型变量名,p,q,r等用作指针变量名。当函数返回值为函数结果状态代码时,
函数定义为Status类型。为了便于描述,除了值调用方式外,增添了C++语言引用调用
的参数传递方式。在形参表中,以&打头的参数即为引用参数*/

在这里插入图片描述

//算法2.9
Status ListInsert_L(LinkList &L,int i,ElemType e)
{
	//在带头结点的单线性链表中第i个位置之前插入元素e
	p=L; j=0;
	while(p&&j<=i-1)
	{
		p=p->next; ++j;//寻找第i-1个节点
	}
	if(!p||j>i-1)return ERROR;//i小于或者大于表长+1
	s=(LinkList)malloc(sizeof(LNode));
	s->data=e;s->next=p->next;
	p->next=s;
	return OK:
}

在这里插入图片描述

//算法2.10
Status ListDelete_L(LinkList &L,int i,ElemType &e)
{
	//在带头结点的但线性表L,中删除第i个元素,并由e返回其值
	p=L; j=0;
	while(p->next&&j<i-1){//寻找第i个结点,并令p指向其前驱
		p=p->next; ++j;
	}
	if(!(p->next)||j>i-1)return ERROR;//删除位置不合理
	q=p->next; p->next=q->next;	//删除并释放结点
	e=q->data;	free(q);
}
//算法2.11
void CreateList_L(LinkList &L,int n)
{
	//逆位序输入n个元素的值,建立带表头结点的单线性链表L
	L=(LinkList)malloc(sizeof(LNode));
	L->next=NULL;	//先建立一个带头结点的单链表
	for(i=n;i>0;--i)
	{
		p=(LinkList)malloc(sizeof(LNode));//生成新结点
		scanf(&p->data);		//输入元素值
		p->next=L->next; L->next=p;	//插入到表头			
	}
}
//算法2.12
void MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc)
{
	//已知单链表La和Lb的元素按非递减排序
	//归并La和Lb得到新的单链表表Lc,Lc的元素也按值非递减排列
	pa=La->next; pb=Lb->next;
	Lc=pc=La;
	while(pa&&pb)
	{
		if(pa->data<=pb->data)
		{
			pc->next=pa;
			pc=pa;
			pa=pa->next;
		}
		else{pc->next=pb;pc=pb;pb=pb->next;}
	}
	pc->next=pa?pa:pb;	//插入剩余段
	free(Lb);		//释放Lb的头结点
}

静态链表

//线性表的静态单链表存储结构
#define MAXSIZE 1000//链表的最大长度
typedef struct
{
	ElemType data;
	int cur;
}component,SLinkList[MAXSIZE];

在这里插入图片描述

//算法2.13
int LocateElem_SL(SLinkList S,ElemTpye e)
{
	//在静态单线性表L中查找第1个值为e的元素
	//若找到,则返回它在L中的位序,否则返回0
	i=S[0].cur;							

//i指示表中的第一个结点
	while(i&&S[i].data!e) i=S[i].cur;	//在表中顺序查找
	return i;
}

在这里插入图片描述

/*【例2-3】运算(A-B)U(B-A)*/
//假设由终端输入集合元素,先建立表示集合A的静态链表S
//而后在输入集合B的元素的同时查找S表,若存在和B相同的元素
//则从S表中删除之,否则将此元素插入S表

//算法2.14 静态单链表的初始化
void InitSpace_SL(SLinkList &space)
{
	//将一位数组space中各个分量链成一个备用链表,space[0].cur为头

指针
	//"0"表示空指针
	for(i=0;i<MAXSIZE-1;i++) space[i].cur=i+1;
	space[MAXSIZE-1].cur=0;
}
//算法2.15 从备用链表中申请一个结点空间
int Malloc_SL(SLinkList &space)
{
	//若备用链表非空,则返回分配的结点的下标,否则返回0
	i=space[0].cur;
	if(space[0].cur) space[0].cur=space[i].cur;
	return i;
}
//算法2.16 将下标为k的空闲空间回收到备用链表
void Free_SL(SLinkList &space,int k)
{
	space[k].cur=space[0].cur; 
	space[0].cur=k;
}
//算法2.17
void differnce(SLinkList &space,int k)
{
	//依次输入集合A和B的元素,在一维数组space中建立表示集合(A-B)U(B-A)
	//的静态链表,S为其头指针。假设备用空间足够大,space[0].cur为其头指针
	InitSpace_SL(space);	//初始化备用空间
	S=Malloc_SL(space);		//生成S的头结点
	r=S;					//r指向S的当前最后结点
	scanf(m,n);				//输入集合A和集合B的元素个数
	for(j=1;j<=m;++j)
	{
		i=Malloc_SL(space);//分配结点
		scanf(space[i].data);//输入A的元素值
		space[r].cur=i;r=1;	//插入到表尾
	}
	space[r].cur=0;		//尾点指针为空
	for(j=1;j<=n;j++)
	{
		//依次输入B的元素值,若不在当前表中,则插入,否则删除
		scanf(b);p=S;k=space[S].cur;//k指向集合中第一个节点
		while(k!=space[k].cur&&space[k].data!b)//在当前表中查找
		{
			p=k;
			k=space[k].cur;
		}//while
		if(k==space[r].cur)//当前表中不存在该元素,插入在r所在结点之后,且r的位置不变
		{
			i=Malloc_SL(space);
			space[i].data=b;
			space[i].cur=space[r].cur;
			space[r].cur=i;
		}//if
		else{				//该元素已在表中,删除它
			space[p].cur=space[k].cur;
			Free_SL(space,k);
			if(r==k) r=p;
		}//else
	}//for
}//difference

循环链表

在这里插入图片描述
在这里插入图片描述

双向链表

//线性表的双向链表存储结构
typedef struct DuLNode
{
	ElemType data;
	struct DuLNode *prior;
	struct DuLNode *next;
}DuLNode,*DuLinkList;

在这里插入图片描述

Status ListDelete_DuL(DuLinkList &L,int i,ElemType &e)
{
	//删除带头结点的双链循环线性表L中第i个元素,i的合法值为1<=i<=表长
	if(!(p=GetElemP_DuL(L,i)))
		return ERROR;
	e=p->data;
	p->prior->next=p->next;
	p->next->prior=p->prior;
	free(p);
	return OK;
}//ListDelete_DuL

在这里插入图片描述

Status ListInsert_DuL(DuLinkList &L,int i,ElemType e)
{
	//在带头结点的双链循环线性表L中第i个位置之前插入元素e
	//i的合法值为1<<i<<表长+1
	if(!(p=GetElemP_DuL(L,i)))//在L中确定插入位置指针p
		return ERROR;
	if(!(s=(DuLinkList)malloc(sizeof(DuLNode))))
		return ERROR;
	s->data=e;
	s->prior=p->prior; p->prior->next=s;
	s->next=p; p->prior=s;
	return OK;
}//ListInsert_DuL

在这里插入图片描述
由于链表在空间的合理利用上和插入、删除时不需移动等优点,
在很多场合下,它是线性表的首选存储结构。然而,它也存在着实现
某些基本操作,如求线性表的长度时不如顺序存储结构的缺点;
另一方面,由于在链表中,结点之间的关系用指针来表示,则数据元素在线性表中的“位序”概念已弱化,而被数据元素在线性表中的“位置”所代替。
为此,从实际应用出发角度重新定义线性表及其基本操作

带头结点的线性链表

//一个带头结点的线性链表类型定义如下
typedef struct LNode
{
	ElemType data;
	struct LNode *next;
}*Link,*Position;

typedef struct		//链表类型
{
	Link head,tail;	//分别指向线性链表中的头结点和最后一个结点
	int len;		//指示线性表中数据元素的个数
}LinkList;
//算法2.21
Status ListInsert_L(LinkList &L,int i,ElemType e)
{
	//在带头结点的单链线性表L的第i个元素之前插入元素
	if(!LocatePos(L,i-1,h)) return ERROR;	//插入位置不合理
	if(!MakeNode(s,e)) return ERROR;		//结点存储分配失败
	InsFirst(h,s);//对于从第i个结点开始的链表,第i-1个结点是它的头结点
	return OK;
}//ListInsert_L
//算法2.21
Status MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc),int (*compare)(ElemType,ElemType))
{
	//已知单链线性表La和Lb的元素按非递减排列
	//归并La和Lb得到的新单链表Lc,Lc的元素值非递减排列
	if(!InitList(Lc)) return ERROR; //存储空间分配失败
	ha=GetHead(La); hb=GetHead(Lb);	//ha,hb分别指向La和Lb的头结点
	pa=NextPos(La,ha); pb=NextPos(Lb,hb);//pa和pb分别指向La和Lb中当前结点
	while(pa&&pb)					//La和Lb均非空
	{
		a=GetcurElem(pa); b=GetCurElem(pb);//a和b为两表中当前比较元素
		if((*compare)(a,b)<=0)
		{
			DeFirst(hb,q);
			Append(Lc,q);
			pa=Nextpos(La,ha);
		}else{
			DeFirst(hb,q);
			Append(Lc,q);
			pb=NextPos(Lb,hb);
		}
	}//while
	if(pa) Append(Lc,pa);		//链接La中剩余结点
	else Append(Lc,pb);        //链接Lb中剩余结点
	FreeNode(ha); FreeNode(hb);//释放La和Lb的头结点
	return OK;
}//MergeList_L

2.4一元多项式的表示及相加

在这里插入图片描述

在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值