数据结构--线性表的链式表示

按位序插入(带头结点)

//在第i个位置插入元素e(带头结点)
bool listInsert(LinkList &L,int i,ElemType e)
{
    if(i<1)
      return false;
      LNode *p;  //指针p指向当前扫描的结点
      int j=0; //当前p指向的是第几个结点
      P=L;//L指向头结点,头结点是第几个0结点(不存数据)
      while (P!==Null&& j<i-1)
      {//循环找到第i-1个结点
      P=p->next;
      j++;
	  }
	  if(P=NULL)//i值不合法
	  	return false;
	 LNode *s=(LNode *)malloc (sizeof(LNode));
	 s->data=e;
	 s->next=p->next;
	 p->next=s;
	 return true;
}
typedef struct LNode{
   ElemType data'
   struct LNode *next;
}LNode,*LinkList;

在这里插入图片描述

按位序插入(不带头结点)

bool listInsert(LinkList &L,int i,ElemType e)
{
    if(i<1)
      return false;
      if(i==1){//插入第一个结点的操作与其他结点操作不同
      LNode *s=(LNode *)malloc (sizeof(LNode));
      s->data=e;
      s->next=L;
      L=s;//头指针指向新结点
      return true;
      }
      LNode *p;  //指针p指向当前扫描的结点
      int j=1; //当前p指向的是第几个结点
      P=L;//P指向第一个结点不是头结点
      while (P!==Null&& j<i-1)
      {//循环找到第i-1个结点
      P=P->next;
      j++;
	 }
	  if(P=NULL)//i值不合法
	  	return false;
	 LNode *s=(LNode *)malloc (sizeof(LNode));
	 s->data=e;
	 s->next=p->next;
	 p->next=s;
	 return true;
}
typedef struct LNode{
   ElemType data'
   struct LNode *next;
}LNode,*LinkList;

在这里插入图片描述

指定结点的后插操作

//后插操作:在P结点之后插入元素e
bool InsertNextNode(LNode *p,ElemType e){
   if (p==Null)
   	return false;
   LNode *s=(LNode *)malloc (sizeof(LNode));
   if(s==Null) //内存分配失配
   	return false;
   s->data=e;//用结点s保存数据元素e
   s->next=p->next;
   p->next=s;//将结点s连到p之后
   return true;
}
typedef struct LNode{
     ElemType data;
     struct LNode *next;
}LNode,*LinkList;

在这里插入图片描述

指定结点的前插操作

//前插操作:在P结点之后插入元素e
bool InsertPriorNode (LNode *P,ElemType e){
	if(P==NULL)
		return false;
	LNode *s =(LNode *)malloc (sizeof(LLNode));
	if(s==NULL)//内存分配失败
	 return false;
	 s->next=P->next;
	 p->next=s;  //新结点S连到P之后
	 s->data=P->data;//将P中的元素复制到S中
	 p->data=e;//P元素覆盖为e
	 return true;
}

在这里插入图片描述

//在P结点之前插入结点S
bool InsertPriorNode (LNode *P,LNode *s){
	if(P==NULL||s=NULL)
		return false;
	 s->next=P->next;
	 p->next=s;  //新结点S连到P之后
	 ElemType temp=p->data;//交换数据域
	 s->data=temp;
	 return true;
}

在这里插入图片描述

封装的好处
小功能模块化,代码逻辑清晰,避免重复代码,简洁易维护

带头结点按位序删除

bool ListDelete(LinkList &L,int i,ElemType &e){
   if(i<1)
   		return false;
   LNode *p;
   int j=0;
   P=L;
   while(P!=NULL&&j<i-1){
   //循环找到第i-1个结点
   P=P->next;
   j+=;
}
if(P==NULL)
	return false;
if(P->next==NULL)
	return false;
	LNode *q=P->next;//令q指向被删除结点
	e=q->data;  //用e返回元素的值
	P->next=q->next;  //将*q结点从链中断开
	free(q);
	return true;
}

在这里插入图片描述
指定结点的删除

//删除指定结点P
bool DeleteNode(LNode *P){
    if(P=NULL)
    	return false;
    LNode *q=P->next;//令q指向*p的后继结点
    P->data=P->next->data;//和后继结点交换数据域
    p->next=q->next;//将*q结点从链中断开
    free(q); //释放后继结点的存储空间
    return true;
}

但是当删除的这个指定结点是最后一个结点时,上述代码却又出现了问题,当是最后的结点时需要特殊讨论。
在这里插入图片描述

单链表按位查找

//按位查找,返回第i个元素(带头结点,把头结点看成第0个结点)
LNode *GetElem(LinkList L,int i){
	if(i<0)
		return NULL;
	LNode *P;//指针P指向当前扫描的结点
	int j=0;//当前P指向的是第几个结点
	P=L;//L指向头结点,头结点是第0个结点不存数据
	whie(P!=NULL&&j<i){
     //循环找到第i个结点
     P=P->next;
     j++;
}
return P;
}

在这里插入图片描述

单链表的按值查找

//按值查找,找到数据域=e的结点
LNode *LocateElem(LinkList L,ElemType e){
   LNode *p=L->next;
   //从第1个结点开始查找数据域为e的结点
   while(P!=NULL&&P->data!=e)
   		P=P->next;
   return P;//找到后返回该点指针,否则返回null
}

在这里插入图片描述

求单链表的长度

//求表的长度
int length(LinkList L)
{
   int len=0; //统计表长
   LNode *P=L;
   while(P->next!=NULL)
   {
   	P=P->next;
   	len++;
   }
   return len;
}

单链表不具有随机访问的特点,只能依次扫描。

尾插法建立单链表
设置一个指向表尾结点的指针

LinkList List_Taillnsert(LinkList &L){
//正向建立单链表
int x;
L=(LinkList)malloc (sizeof(LNode));//初始化空表建立头结点
LNode *s,*r=L;  //r为表尾指针
scanf("%d",&x);
while(x!=9999){
   s=(LNode *)malloc (sizeof(LNode));
   s->data=x;
   r->next=s;//在r结束之后插入元素x
   r=s;//r指向新的表尾元素,永远保持r指向最后一个结点
   scanf("%d",&x);
}
r->next=NULL;//尾结点指针置空
return L;
}

头插法建立单链表(主要应用于链表的逆置)

LinkList List_HeadInsert(LinkList &L){
   //逆向建立单链表
   LNode *s;
   int x;
   L=(LinkList)malloc(sizeof(LNode));//创建头结点
   L->next=NULL;  //初始化为空链表
   scaanf("%d",&x);
   while(x!=9999)
   {
   s=(LNode *)malloc(sizeof(LNode));
   s->data=x;
   s->next=L->next;
   L->next=s;
   scanf("5d",&x);
}
	return L;
}

双链表

//双链表的定义
typedef struct DNode{
   Elemtype data;
   struct DNode *prior,*next;
}DNode,*DLinklist;

在这里插入图片描述

带结点的双链表的初始化

bool Initlinklist(Dlinklist &L){
      L=(DNode*)malloc(sizeof(DNode));//malloc分配一个头结点
      if(N==null)
      	return false;
      L->prior=null;
      L->next=null;
      return true;
}
//判断带头结点的双链表是否为空
bool empty(Dlinklist L){
     if(l->next==null)
     	return true;
     else
     	return false;
}

在这里插入图片描述

双链表的插入

bool InsertNextDnode(Dnode *p,Dnode *s){
	if(p==null||s==null)
		return false;
    s->next=p->next;
    if(p->next!=null)//如果p结点有后继结点
    	p->next->prior=s;
    s->prior=p;
    p->next=s;
    return true;    
}

在这里插入图片描述

双链表的删除

//删除p的后继结点Q
bool DeleteNextDnode(Dnode *p){
	if(p==null) return false;
	Dnode *q=p->next;//找到p的后继结点q
	if(q==null) return false;
	p->next=q->next;
	if(q->next!=null)
		q->next->prior=p;
	free(q);
	retutn true;
}

在这里插入图片描述
销毁双链表

void Destory(Dlinklist &L)
{
   //循环释放各个数据结点
   while(L->next!=null)
   		DeleteNextDnode(L);
   	free(L);//释放头结点
   	L=NULL;//头结点指向null
	
}

在这里插入图片描述
双链表的遍历

//后向遍历
while(p!=null){
   //对下相应的结点处理
   p=p->next;
}
//前向遍历
while(p->prior!=null){
   //对下相应的结点处理
   p=p->prior;
}

双链表不可随机存取、按位查找、按值查找等操作都只能用遍历的方式去实现,其时间复杂度为O(n)
循环遍历单链表

typedef struct LNode{
  elemtype data;
  struct Lnode *next;
}Lnode,*linklist;
//初始化一个循环单链表
bool InitList(Linklist &L){
   L=(LNode *malloc(sizeof(LNode)));//分配一个头结点
	if(L==null)
		return false;
	L->next=L;
	return true;
}

在这里插入图片描述
循环双链表

//初始化空的循环双链表
bool InitDlinklist (Dlinklist &L){
   L=(Dnode*)malloc(sizeof(Dnode));
   if(L==null)
   	return false;
   L->prior=L;
   L->next=L;
   return true;
}

在这里插入图片描述
双链表的插入

//在P结点之后插入S结点
bool INsertNextDnode(Dnode *P,Dnode *S)
{
   S->next=P->next;
   P->next->prior=S;
   S->prior=P;
   P->next=S;
}
//判断循环双链表是否为空
bool Empty(Dlinklist L){
   if(L->next==L)
   	return true;
   else
   	return false;
}
//判断结点P是否为循环双链表的表尾结点
bool isTail(Dlinklist L,Dnode *p){
  if(P->next==L)
  	return false;
  else
  	return false;
}

在这里插入图片描述
双链表的删除

//删除P的后继结点Q
P->next=q->next;
q->next->prior=P;
free(q);

在这里插入图片描述
静态链表
分配一整片连续的内存空间,各个结点集中安置
优点:增删操作不需要大量移动元素
缺点:不能随机存取只能从开头依次往后,容量固定不可变

//用代码定义一个静态链表
#define Maxsize 10
struct Node{
   ElemType data;
   int next;//下一个元素的数组下标
};
//重命名
typedef struct Node SLinklist[MaxSize];

在这里插入图片描述
初始化静态链表:把a[0]的next设为-1(代表空结点null),把其他结点的next设为一个特殊值用来表示结点空闲如-2
查找:从头结点出发挨个往后遍历结点,其时间复杂度为O(n)
插入位序为i的结点
1)先找到一个空的结点,存入数据元素
2)从头结点出发找到位序为i-1的结点
3)修改新结点后的next
4)修改i-1号结点的next
删除结点:
1)从头结点出发找到前驱结点
2)修改前驱结点的游标
3)把被删除结点的next设为-2

在这里插入图片描述

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
线性是一种常见的数据结构,它表示具有相同数据类型的一组元素的有序序列。线性中的元素之间存在一种顺序关系,每个元素都有一个前驱和一个后继(除了第一个元素没有前驱,最后一个元素没有后继)。线性可以用顺序存储结构或链存储结构实现。 在顺序存储结构中,线性的元素按照顺序存储在连续的内存空间中,可以通过元素的下标来访问和操作元素。插入或删除元素时,需要移动其他元素,因此操作的时间复杂度较高。 链存储结构中,线性的每个元素都包含一个数据域和一个指针域,指针指向下一个元素。通过指针的链接,元素可以按照任意顺序存储在内存中,插入和删除操作只需要改变指针的指向,因此时间复杂度较低。 线性常见的操作包括插入、删除、查找、获取长度等。其中插入和删除操作需要注意保持线性的顺序关系。 常见的线性有数组、链、栈和队列。数组是最简单的线性,通过下标可以直接访问元素;链是动态存储结构,插入和删除操作方便,但访问元素需要遍历链;栈是一种特殊的线性,只允许在的一端进行插入和删除操作;队列也是一种特殊的线性,只允许在的一端进行插入操作,在另一端进行删除操作。这些数据结构在实际应用中都有各自的应用场景和优缺点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃香菜的斌斌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值