python 数据结构之线性表

线性表的概念

线性表的定义: 线性表是n个类型相同数据元素的有限序列,对n>0,除第一元素无直接前驱、最后一个元素无直接后继外,其余的每个数据元素只有一个直接前驱和一个直接后继。
线性表的特点:
(1)同一性。线性表由同类数据元素组成,每一个ai必须属于同一数据类型
(2)有穷性。线性表由有限个数据元素组成,表长度就是表中数据元素的个数。
(3)有序性。线性表中相邻数据元素之间存在着序偶关系<ai ai+1>
线性表的分类: 顺序表和链表

顺序表

顺序表(顺序存储结构的线性表):用一组地址连续的存储单元依次存储线性表中的各个元素,使得线性表中在逻辑结构上相邻的数据元素存储在连续的物理存储单元中,即通过数据元素物理存储的连续性来反映数据元素之间逻辑上的相邻关系。例如:c语言中的数组
c语言定义线性表的顺序存储结构:

#define MAXSIZE 100             /*此处的宏定义常量表示线性表的最大长度*/
typedef struct
{
	ElemType elem[MAXSIZE];		/*线性表占用的数组空间*/
	int last;				    /*纪录线性表中最后一个元素在数组elem[]中的位置*/
}SeqList;

如何定义变量:
(1)通过变量定义语句: SeqList L;
将L定义为SeqList类型的变量,利用L.elem[i-1]来访问顺序表中序号为i的元素ai;通过L.last可得到顺序表中最后一个元素的下标,而L.last+1就是顺序表的长度。
(2)通过 指针变量定义语句:
SeqList L1,*L;
L=&L1;
将L定义为指向SeqList类型的指针变量,使用时,可通过L->elem[i-1]来访问顺序表中序号为i的元素ai,使用L->last+1得到顺序表的长度。
顺序表的基本运算:
1.查找
从第一个元素开始,依次将表中元素和e相比较,若相等,则查找成功,返回该元素在表中的序号;若e与表中的所有元素都不相等,则查找失败,返回-1。

int Locate(SeqList L,ElemType e)
{ 
	i=0;
	while((i<=L.last)&&(L.elem[i]!=e))
		i++;
	if(i<=L.last)				/*找到元素*/
		return(i+1);
	else						/*未找到元素*/
		return(-1);

2.插入
在表的第i(1≤i≤n+1)个位置前插入一个新元素e,使长度为n的线性表变成长度为n+1的线性表。即将原表中位置i,…n-1,n上的结点,依次后移到位置 i+1,…n,n+1上,空出第i个位置,然后在该位置上插入新结点e。当i=n+1时,是指在线性表的末尾插入结点,所以无需移动结点,直接将e插入表的末尾即可。

int InsList(SeqList *L,int i,ElemType e)
{
	int k;
	if((i<1)||(i>L->last+2))
	{
		printf("插入位置i值不合法")return(0);
	}
	if(L->last>=MAXSIZE-1)
	{
		printf("表已满,无法插入")return(0);
	}
	for(k=L->last;k>=i-1;k--)
		L->elem[k+1]=L->elem[k];
	L->elem[i-1]=e;
	l->last++;
	return(1);
}

3.删除
将表的第i(1≤i≤n)个元素删去,使长度为n的线性表变成长度为n-1的线性表。即将原表中位置在i+1,i+2…,n-1,n上的结点,依次前移到位置i,i+1,…n-1。

int DelList(SeqList *L,int i,ElemType *e)
{
	int k;
	if((i<1)||(i>L->last+1))
	{
		printf("删除位置不合法!")return(0)}
	*e=L->elem[i-1];
	for(k=i;i<L->last;k++)
		L->elem[k-1]=L->elem[k];
	L->last--;
	return(1);
}                                                    

4.合并
LC是一个空表,为使元素非递减排列,可设两个指针i、j分别指向表LA和LB中的元素,若LA.elem[i]>LB.elem[j],则先将LB.elem[j]插入到表LC中,若LA.elem[i]≤LB.elem[j],则将LA.elem[i]插入到表LC中,如此进行下去,直到其中一个表被扫描完毕,然后再将未扫描完的表中剩余的所有元素放到表LC中。(顺序表LA、LB中元素非递减排列)

void mergeList(SeqList *LA,SeqList *LB,SeqList *LC)
{
	int i,j,k,l;
	i=0;j=0;k=0;
	while(i<=LA->last && j<=LB->last)
	if(LA->elem[i]<=LB->elem[j])
	{
		LC->elem[k]=LA->elem[i];
		i++;k++;
	}
	else
	{
		LC->elem[k]=LB->elem[j];
		j++;k++;
	}
	while(i<=LA->last)
	{
		LC->elem[k]=LA->elem[i];
		i++;k++;
	}
	while(j<=LB->last)
	{
		LC->elem[k]=LB->elem[j];
		j++;k++;
	}
	LC->last=LA->last+LB->last+1;
}

链表

链表(链式存储结构的线性表):用一组任意的存储单元来存放线性表的结点,这组存储单元可以是连续的,也可以是非连续的,甚至是零散分布在内存的任何位置上。链表中结点的逻辑顺序和物理顺序不一定相同。
单链表
结点包括两个域:数据域用来存储结点的值,指针域用来存储数据元素的直接后继的地址。
单链表指的是每个结点只有一个next指针域的链表。
单链表的存储结构:

typedef struct Node
{	ElemType data;
	struct Node *next;
}Node,*LinkList;

单链表上的基本运算
1.初始化

InitList(LinkList *L)
{
	*L=(LinkList)malloc(sizeof(Node));
	(*L)->next=NULL;
}

2.建立
(1)头插法建表

void CreateFromHead(LinkList L)
{	
	Node *s;
	char c;
	int flag=1;
	while(flag)
	{
		c=getchar();
		if(c!='$')             /*结束标志*/
		{
			s=(Node*)malloc(sizeof(Node));
			s->data=c;
			s->next=L->next;
			L->next=s;
		}
		else flag=0;
	}
}

(2)尾插法建表

void CreateFromTail(LinkList L)
{
	Node *r,*s;
	int flag=1;
	r=L;
	while(flag)
	{
		c=getchar();
		if(c!='$')
		{
			s=(Node *)malloc(sizeof(Node));
			s->data=c;
			r->next=s;
			r=s;
		}
		else
		{
			flag=0;
			r->next=NULL;
		}
	}
}

3.查找
(1)按序号查找
在单链表中查找第i个结点(从头结点开始扫描)

 Node *Get(LinkList L,int i)
 {
 	int j;
 	Node *p;
 	if(i<=0)
 		return 0;
 	p=L;j=0;
 	while((p->next!=NULL)&&(j<i))
 	{
 		p=p->next;
 		j++;
 	}
 	if(i==j)
 		return p;
 	else
 		return 0;
 }

(2)按值查找
在单链表中查找值为key的结点

Node *Locate(LinkList L,ElemType key)
{
	Node *p;
	p=L->next;
	while(p!=NULL)
	{
		if(p->data!=key)
			p=p->next;
		else
			break;
	}
	return p;
}

4.求单链表长度

int ListLength(LinkList L)
{
	Node *p;
	p=L->next;
	j=0;
	while(p!=NULL)
	{
		p=p->next;
		j++;
	}
	return j;
}

5.插入

void InsList(LinkList L,int i,ElemType e)
{
	Node *p,*s;
	int j;
	if(i<=0)
		return 0;
	p=L; j=0;
	while(p!=NULL&&j<i-1)
	{
		p=p->next;
		j++;
	}
	if(p==NULL)
	{
		printf("插入位置不合理!")return 0;
	}
	s=(Node *)malloc(sizeof(Node));
	s->data=e;
	s->next=p->next;
	p->next=s;
	return 1;
}

6.删除

int DelList(LinkList L,int i,ElemType *e)
{
	Node *p,*r;
	int j;
	p=L;k=0;
	while(p->next!=NULL&&j<i-1)
	{
		p=p->next;
		j++;
	}
	if(p->next==NULL)
	{
		printf("删除结点的位置i不合理!")return 0;
	}
	r=p->next;
	p->next=r->next;
	*e=r->data;
	free(r);
	return 1;
}

7.合并

LinkList MergeLinkList(LinkList LA,LinkList LB)
{
	Node *pa,*pb;
	LinkList LC;
	pa=LA->next;
	pb=LB->next;
	LC=LA;
	LC->next=NULL;r=LC;
	while(pa!=NULL&&pb!=NULL)
	{
		if(pa->data<=pb->data)
		{
			r->next=pa;
			r=pa;
			pa=pa->next;
		}
		else
		{
			r->next=pb;
			r=pb;
			pb=pb->next;
		}
	}
	if(pa)
		r->next=pa;
	else
		r->next=pb;
	return(LC);
}

循环链表
循环链表是一个首尾相接的链表,将单链表最后一个结点的指针域由NULL改为指向表头结点,就得到了单链形式的循环链表,并称为循环单链表。同样,还可以有多重链的循环链表。
1.初始化

InitList(LinkList *CL)
{
	*CL=(LinkList)malloc(sizeof(Node));
	(*CL)->next=*CL;
}

2.建立

void CreateCLinkList(LinkList CL)
{
	Node *r,*s;
	char c;
	r=CL;						/*r指针动态指向链表的当前表尾,其初值指向头结点*/
	c=getchar();
	while(c!="$')
	{
		s=(Node*)malloc(sizeof(Node));
		s->data=c;
		r->next=s;
		r=s;
		c=getchar();
	}
	r->next=CL;
}

3.合并

LinkList merge(LinkList LA,LinkList LB)
{
	Node *p,*q;
	p=LA;
	q=LB;
	while(p->next!=LA)			/*找到表LA的表尾,用p指向它*/
		p=p->next;				
	while(q->next!=LB)			/*找到表LB的表尾,用q指向它*/
		q=q->next;
	q->next=LA;					/*修改表LB的尾指针,使之指向表LA的头结点*/	
	p->next=LB->next;			/*修改表LA的尾指针,使之指向表LB中的第一个结点*/
	return(LA);
}

双链表
在单链表的每个结点里再增加一个指向其前驱的指针域prior,这样形成的链表中就有两条方向不同的链,称之为双链表。
1.插入
在这里插入图片描述

int DlinkIns(DoubleList L,int i,ElemType e)
{
	DNode *s,*p;
	...
	...
	s=(DNode*)malloc(sizeof(DNode));
	if(s)
	{
		s->data=e;
		s->prior=p->prior;
		p->prior->next=s;
		s->next=p;
		p->prior=s;
		return 1;
	}
	else
		return 0;
}

2.删除
在这里插入图片描述

int DlinkDel(DoubleList L,int i,ElemType *e)
{
	DNode *p;
	...
	...
	*e=p->data;
	p->prior->next=p->next;		/*第①步*/  
	p->next->prior=p->prior;	/*第②步*/ 
	free(p);
	return 1;
}
发布了11 篇原创文章 · 获赞 1 · 访问量 236

猜你喜欢

转载自blog.csdn.net/weixin_41708548/article/details/104066163