线性表的表示和实现

Posted 咖啡壶子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线性表的表示和实现相关的知识,希望对你有一定的参考价值。

1.线性表的特点和基本操作

线性表的基本特点
1.集合中必存在唯一的一个“第一元素”。

2.集合中必存在唯一的一个 “最后元素” 。

3.除最后一个元素之外,均有唯一的后继。

4.除第一个元素之外,均有唯一的前驱。

线性表、包括顺序表和链表,顺序表里面元素的地址是连续的。链表里面节点的地址不是连续的,是通过指针连起来的。

线性表的基本操作
  1. InitList(&L)
    操作结果:构造一个空的线性表L。

  2. DestroyList(&L)
    初始条件:线性表L已存在。
    操作结果:销毁线性表L。

  3. ListEmpty(L)
    初始条件:线性表L已存在。
    操作结果:若L为空表,则返回TRUE,否则返回FALSE。

  4. ListLength(L)
    初始条件:线性表L已存在。
    操作结果:返回L中数据元素的个数。

  5. GetElem(L, i, &e)
    初始条件:线性表L已存在, 1≤i ≤ ListLength(L) 。
    操作结果:用e返回L中第i个数据元素的值。

  6. LocateElem(L, e, compare())
    初始条件:线性表L已存在,compare()是数据元素判定函数。
    操作结果:返回L中第1个与e满足compare( )的数据元素的位序。若这样的元素不存在,则返回值为0。

  7. PriorElem(L, cur_e, &pre_e )
    初始条件:线性表L已存在。
    操作结果:若cur_e是L中的数据元素,且不是第一个,则用pre_e返回它的前驱,否则操作失败,pre_e无定义。

  8. NextElem(L, cur_e, &next_e)
    初始条件:线性表L已存在。
    操作结果:若cur_e是L中的数据元素,且不是最后一个,则用next_e返回它的后继,否则操作失败,next_e无定义。

  9. ListTraverse(L, visit( ))
    初始条件:线性表L已存在。
    操作结果:依次对L中的每个数据元素调用函数visit( )。一旦visit( )失败,则操作失败。
    /* 以上除了初始化和销毁操作其他都是引用型操作 */

  10. ClearList(&L)
    初始条件:线性表L已存在。
    操作结果:将L重置为空表。

  11. ListInsert(&L, i, e)
    初始条件:线性表L已存在,1≤i≤Listlength(L)+1。
    操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1。

  12. ListDelete(&L, i, &e)
    初始条件:线性表L已存在且非空,1≤i≤Listlength(L)。
    操作结果:删除L中第i个数据元素,并用e返回其值,L的长度减1。
    }ADT List

2.线性表的顺序表示和实现

①顺序表的存储结构

#define  MAXSIZE	100 //顺序表的最大容量
typedef  struct{
	ElemType  *elem;	//顺序表在内存的基址
	            int 	length;	//当前顺序表的长度,即表中存放元素的个数
}SqList;	//顺序表的结构类型名为SqList

②初始化InitList

1. 初始化:创建一个空的顺序表
Status  InitList(SqList &L) {	//构造一个空的顺序表L
	L.elem=new ElemType[MAXSIZE];
	if(!L.elem) exit(OVERFLOW);	//分配失败
	L.length=0;	//空表长度为0
	return OK;
} //InitList

③取值GetElem

2. 取值:获取表中第i个数据元素的值
Status GetElem(SqList L, int i, ElemType &e){
 //若i<1或i大于表长,返回ERROR;否则用e返回第i个元素的值,并返回OK
 if(i<1||i>L.length) return ERROR; //i值不合法,返回ERROR
 e=L.elem[i-1]; //将第i个元素值赋给e
 return OK;
}//GetElem

基本操作:元素的赋值
赋值次数:1
时间复杂度:O(1)

④修改ModifyElem

修改:将表中第i个数据元素的值改为指定值
status ModifyElem(SqList &L, int i, ElemType e){
 //在顺序表L中修改第i个元素,且1≤i≤ListLength_Sq(L)
 if(i<1||i>L.length) return ERROR; //i值不合法,返回ERROR
 *(L.elem+i-1) =e; //将指定元素值赋给第i个元素
 return OK;
}//ModifyElem

基本操作:元素的赋值
赋值次数:1
时间复杂度:O(1)

⑤查找LocateElem

3.查找:查找指定元素e

int LocateElem(SqList L, ElemType e){
 //在顺序表L中查找第1个值与e相等的元素的位序,若找到,返回其在L中的位序,否则返回0。
	for(i=0;i<L.length;i++) if(e==L.elem[i])  return i+1;
	return 0;
} //LocateElem

基本操作:元素的比较
最坏情况下比较的次数:n
平均比较次数:(n+1)/2
时间复杂度:O(n)

⑥插入ListInsert

4. 插入:将指定元素e插入到指定位置

Status  ListInsert ( SqList &L, int i, ElemType e) {
//在顺序表L的第i个位置插入新的数据元素e,且1≤i≤ListLength(L)+1
	if(i<1||i>L.length+1)  return  ERROR;
	if(L.length==MAXSIZE)  return  ERROR;    //当前存储空间已满
	for(j=L.length-1; j>=i-1; j--)  
		L.elem[j+1]=L.elem[j];   //插入位置及其后的元素后移
	L.elem[i-1]=e;	//插入元素e
	L.length++//表长加1
	return OK;
} //ListInsert


基本操作:元素的移动
最坏情况下移动的次数:n
平均移动次数:

时间复杂度:O(n)

⑦删除ListDelete

5. 删除:将指定位置元素e删除
   操作特点:插入位置后面的元素均需前移一个位置
   合法的删除位置:1≤i≤ListLength(L)
Status  ListDelete(SqList &L, int i) {
//在顺序表L中删除第i个元素并用e返回其值,且1≤i≤ListLength_Sq(L)
	if(i<1||i>L.length)  return ERROR; 	//删除位置不合法
	for(j=i; j<=L.length-1; j++)  
		L.elem[j-1]=L.elem[j];  //被删除元素之后的元素向前移一个位置
	--L.length; 	//表长减1
	return OK;
} //ListDelete

基本操作:元素的移动
最坏情况下的移动次数:n-1
平均移动次数:

时间复杂度:O(n)

3.线性表的链式表示和实现

①链式存储结构特点

链式存储结构特点:用一组任意的存储单元存储线性表的数据元素(这组存储单元可以连续,也可以不连续)。
• 单链表可由一个头指针唯一确定。
• 若要访问数据元素ai,须从头指针出发,顺着指针域逐个访问,直至第i个结点。因此,线性表的链式存储结构只适合顺序访问,不支持直接访问。

单链表有两种形式:不带头结点的单链表和带头结点的单链表。

②单链表的存储结构

typedef  struct LNode{
	ElemType   	data;	 //数据域
	struct LNode    *next; 	//直接后继:指向下一个结点的指针
}LNode,   *LinkList;

③初始化InitList

1. 初始化:创建一个带头结点的空链表
status  InitList(LinkList &L) {	//构造一个空的链表L
	L=new LNode; 	//生成新结点
	if(!L) exit(OVERFLOW);	//分配失败
L->next=NULL;	//空表长度为0
return OK;
} //InitList

④取值GetElem

//L为带头结点的单链表头指针,当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR
status GetElem(LinkList L, int i, ElemType &e) {	
p=L->next; j=1; //p指向首元结点,j为计数器
while( p&&j<i ) { p=p->next; ++j; } //顺指针向后查找直至第i个元素或表尾
if( !p || j>i )return ERROR; 
e=p->data; 
return OK;
} //GetElem_L

基本操作:指针后移
若1≤i≤n,指针移动i-1次,否则移动0次或n次
最坏情况下移动的次数:n(表中不存在第i个元素时)
时间复杂度:O(n)

⑤查找

3. 查找:查找链表中与给定元素e的值相等的元素的位置
LNode  *LocateElem(LinkList L, ElemType e){	
  //在带头结点的单链表L中查找第1个数据元素为e的,若找到则返回该元素结点的地址(指针类型),否则返回NULL。
	p=L->next;  		//p指向首元结点
	while( p&&p->data!=e )   p=p->next; 
	return p;	
} //LocateElem_L

基本操作:元素的比较
最坏情况下的比较次数:n
平均比较次数:(n+1)/2
时间复杂度:O(n)

⑥插入ListInsert

4. 插入:将值为e的元素插入到指定位置
status  ListInsert( LinkList &L, int i, ElemType e){
//在带头结点的单链表L中第i个位置之前插入元素e,1≤ i≤表长+1
	p=L; j=0;
	while( p&&j<i-1 ) { p=p->next; j++; } 	//顺指针找第i-1个结点
	if( !p || j>i-1 )	return ERROR; 		//i大于表长加1或i小于1
	s=new LNode; 	//生成新结点
	s->data=e;
	s->next=p->next; 	//插入L中
	p->next=s;
	return OK;
} //ListInsert

基本操作:指针后移
当1≤i ≤表长+1时,指针后移i-1次,否则,后移0或n+1次
时间复杂度:O(n)

⑦删除ListDelete

5. 删除:删除指定位置/值的元素
status  ListDelete(LinkList &L, int i, ElemType &e) {
//在带头结点的单链表L中,删除第i个元素,并用e返回其值
	p=L;     j=0;
	while( p->next && j<i-1 ) {p=p->next; j++;} //顺指针找第i-1个结点
	if( !(p->next) || j>i-1 ) return ERROR; 	//i小于1或i大于表长
	q=p->next; 	//q指向第i个结点
	p->next=q->next; 
	e=q->data;
	free(q);  	//释放所删结点的空间
	return OK;
} //ListDelete

基本操作:指针后移
当1≤i ≤表长时,指针后移i-1次,否则后移0或n次
时间复杂度:O(n)

⑧创建单链表CreatList_R

6. 创建单链表:后插法
void CreatList_R(LinkList &L, int n) {
//正位序输入n个元素的值,建立带头结点的单链线性表L
	L=new LNode;
	L->next=NULL; //空链表
	q=L;
	for(i=0; i<n; i++){
		p= new LNode;
		cin>> p->data;
		p->next=NULL;
		q->next=p; //将新结点插入在表尾
		q=p;
	}
} //CreatList_R

⑨双向链表的存储结构

typedef  struct DuLNode{
	ElemType  		data;    	//数据域
     struct   DuLNode  	*prior; 	//直接前驱
	struct   DuLNode  	*next; 	//直接后继
}DuLNode, *DuLinkList;

⑩双向链表插入节点ListInsert_DuL

status  ListInsert_DuL (DuLinkList  &L, int i, ElemType e) {
//在带头结点的双向循环链表L中第i个位置之前插入元素e,i的合法值为1≤i ≤表长加1。
	p=L->next; j=1;
	while(p!=L&&j<i) {p=p->next; j++; }	
//查找第i个结点的位置,即插入位置,而不是找前驱结点
	if(j!=i) return ERROR;		//i值不合法
	s=new DuLNode; 	//生成新结点
	s->data=e;
	s->prior=p->prior;	p->prior->next=s;	 //插入
	s->next=p;  		p->prior=s; 		
	return OK;
} //ListInsert_DuL

⒒双向链表删除节点

status  ListDelete_DuL(DuLinkList &L, int i, ElemTypw &e) {
//删除带头结点的双向循环链表中第i个元素,i的合法值为1≤i ≤表长
	p=L->next; j=1;
	while(p!=L&&j<i) {p=p->next; j++;} 	
//查找第i个结点的位置,即插入位置,而不是找前驱结点
	if(p==L||j>i)  return ERROR; 	//i值不合法
	e=p->data;
	p->prior->next=p->next; 	//删除第i个结点
	p->next->prior=p->prior;
	free(p); 	//释放结点空间
	return OK;
} //ListDelete_DuL

4.顺序表和链表的比较

以上是关于线性表的表示和实现的主要内容,如果未能解决你的问题,请参考以下文章

线性表的链式表示和实现(插入删除建空)

线性表的顺序表示的简单实现(顺序表的实现)

数据结构_线性表的顺序表示和链式表示

线性表的顺序表示和实现

线性表的链式表示和实现

《线性表的插入和删除算法实现》以及《栈和队列的插入和删除算法实现》的c语言代码