单链表(算法与数据结构)

 链表
①非连续的内存单元–逻辑相邻元素的物理位置不一定相邻;
②结点构成:在数据之外,附加指针->指示逻辑关系、存储地址

 单链表
为每个结点新增1个指针域,每个结点包括两个域:
①数据域:存放元素本身信息
②指针域:存放后继结点的存储位置;
指向链表中第一个结点的指针,称为这个链表的头指针。
最后一个元素的指针不指向任何结点,称为空指针,图示中用“^”表示,在算法中用“NULL”表示

 带头结点的单链表
头结点:
– 可以不存信息,可以保存与整个表相关的信息,如表长;
– 空表的头结点指针域为空null;
– 在k0处插入、删除都不影响头指针的值;
– 辅助结点,不属于表的内容
– Link域指向表的第一个实际结点

 单链表定义(C语言描述)

struct Node; //单链表结点类型
typedef struct Node * PNode; //结点指针类型(PNode是个指针,指向struct Node)
struct Node
{ DataType info;  //数据域(info是DataType类型)
  PNode link; //指针域,可指向一个结点,link是PNode类型
};
typedef struct Node * LinkList; //结点指针类型,C语言当中实际使用的是LinkList指针
LinkList llist; //llist为单链表的头指针

 单链表运算的实现

  1. 创建空表
    ①声明头指针
    ②为头结点申请空间
    ③设置头结点的指针域
LinkList createNullList_link(void)
{ LinkList  llist;
  llist = (LinkList )malloc(sizeof(struct Node));
  if(llist != NULL) //头结点空间分配成功
    llist->link = NULL; // llist->link有意义,才能用
  else printf(“out of space!\n”);  
  return llist; //返回头指针
 }
  1. 判断是否为空表
    检查头结点的指针域 llist->link 是否为空
int isNullList_link(LinkList  llist)
{   
      return ( llist->link == NULL) ;
}
  1. 查找元素、求某元素的存储位置
PNode locate_link(LinkList llist, DataType x)
{ PNode p; 
  if(llist == NULL)   return NULL;
p= llist->link; //p指向第1个结点
while( p !=NULL && p->info !=x)
      p= p->link; //若未找到,游历指针右移
  return (p);
}
  1. 在单链表中插入元素
     在指针p所指结点之后,插入元素x
    ①申请新结点q,置其数据域为x;
    ②q挂到链表上:q的指针域指向p的后继;
    ③p的指针域指向q,原链自动断开;
int insertPost_link(LinkList llist, PNode p,DataType x)
{ PNode q = (PNode)malloc(sizeof(struct Node));
   if (q == NULL) //若空间分配失败
      { printf(“Out of space!\n”);   return(0);}
else
      { q->info=x;  //设置新结点q
        q->link = p->link;  //q链入原链表
        p->link = q;  //完成新链表
      }
 }

 在指针p所指结点之前,插入元素x
①找到p的前驱p1
②申请新结点q,置其数据域为x;
③q挂到原链表:q的指针域指向p;
④p1的指针域指向q,原链自动断开;

寻找指针p所指结点的前驱:
从第1个结点开始,检查各结点的指针域?=p

PNode locatePre_link(LinkList llist, PNode p)
{ if(llist==null)    return null; 
  PNode p1= llist; //游历指针p1指向头结点
while( p1!=null&&p1->link!=p)
      p1= p1->link;//若后继不是p, 则指针右移
return p1;
}

寻找值为x的结点的前驱:
从第1个结点开始,检查各结点的数据域?=x

 在带头结点单链表中,第i+1个结点之前,(顺序表中下标为i的元素ki)之前,插入元素x
– 借助计数器 int j=0 寻找下标为i-1的元素

int insert_link(LinkList llist, int i,  DataType x) 
{ PNode p, q; //游历指针
  p= llist; //p指向头结点 
  int j =0; //声明计数器 
while(p!=NULL&& j<i) //当计数未达到, 指针右移
         { p= p->link;   j=j+1;}  
if (p==NULL || j!=i) //若未找到下标为i-1的元素
     { printf(“i =%d is illegal !\n”, i); 
       return 0; }//若成功找到下标为i-1的结点(p正指向它)
q=(PNode)malloc(sizeof(struct Node)); 
if (q==NULL)
    { printf(“Out of space!\n”);   return 0; }
else//在p之后 插入新结点
    { q->info=x;
      q->link = p->link ;
      p->link = q; }
 return 1;
}
  1. 从单链表中删除元素
    从单链表中删除第1个值为x的结点
    ①遍历,查找x (地址为q),其前驱p;
    ②从链表中删除x
    ③释放x结点占用的内存空间
int deleteV_link(LinkList llist, DataType x)
{ PNode p=llist, q;
   while( p->link !=NULL && p->link->info !=x)
              p= p->link; //从头开始寻找x
   if (p->link ==NULL) //判断是否找到x
      { printf(“x does not exist! \n”);    return 0; }
   else//找到x,且p指向x的前驱
      { q = p->link; 
        p->link = q->link; //删除q
        free(q);
        return 1; }
  }

 单链表代价分析
在单链表中查找第一个值为x的元素:
---- 从头结点开始,遍历、匹配
---- 时间复杂度为O(n)
在单链表中查找第i个元素:
---- 从头结点开始,借助计数器j, 遍历
---- 时间复杂度为O(n)

 单链表分析与评价
优点:
插入或删除,只需修改指针,无需移动元素;
动态分配存储空间;
缺点:
存储密度比顺序表低;
不能随机访问第i个元素,需顺链查找;

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值