数据结构C(一)——线性表的链式存储

线性表的基础知识

  1. 什么线性表,线性表的定义?
    线性表是由n个数据类型相同的数据元素构成的有限序列,记作(a1,a2,…,ai-1,ai,ai+1, …,an)。
  2. 线性表的基本特征?
    ①数据元素之间是一对一关系(线性)
    ②除第一个元素外每个元素都有一个前驱,出最后一个元素外每个元素都有一个后继。

线性表的链式存储

  1. 什么是链表?
    采用链式存储的线性表称为链表。

  2. 链表有哪些分类?
    从实现角度分为:动态链表(free,malloc),静态链表
    从链接方式分为:单链表,循环链表,双向链表

这里主要学习从链接方式分类学习线性表的链式存储

单链表

  1. 单链表的定义
    用一组地址任意的存储单元来存储线性表中的元素,每个元素信息由数据域和指针域构成(用指针域来表示元素之间的逻辑关系),这两部分构成的存储映像称为结点,由于每个节点的指针域只有一个,故称为单链表。
    数据结构C(一)——线性表的链式存储_第1张图片
    注意:为了便于对链表进行操作,通常会设置头节点。

  2. 单链表结构存储示意图
    数据结构C(一)——线性表的链式存储_第2张图片

  3. 单链表上的基本运算基本运算:建表,增删改查

  4. 具体操作

(1)插入数据
需求:链表中第 i 个结点之前插入结点e
算法思想:在链表中第 i 个结点之前插入结点需要找到并修改第 i-1 个结点的指针。首先将结点e的指针域指向结点i,再将结点i-1的指针域指向e。

注意:不能先将结点i-1的指针域指向结点e,这样会丢失结点i的存储地址信息。

算法实现:

int InsNode(LinkList L,int i,ElemType e )  //调用函数时,传输数据。在链表L中,第i个元素前插入元素e
{    Node *pre,*s;   
     pre=Get(L,i-1);  //get函数获取获取到结点的 i-1的指针位置,该指针指向i节点的位置
     if(!pre)          
     {       print("不能插入");         
              return error;   
       }   
    s=(Node*)malloc(sizeof(Node));   //将一个结点长度的内存空间,经过malloc转换为指针型,s表示插入元素e的指针   
    s->date=e;  //将e赋值给s的数据域  
    s->next=pre->next;     
    pre->next=s;    
    return ok;   
  }

(2)建立单链表

头插法建表操作方法:
①首先要建立一个“空表”(头指针)
②输入数据元素an,建立结点并插入;
③输入数据元素an-1,建立结点并插入;
④依次类推,直至输入完a1结束。类似于上面讲的插入数据。

算法实现:

Linklist Createfromhead()
 {	Linklist L; 
         Node *s; 
         int x;	
         L=(Linklist)malloc(sizeof(Node));   //初始化链表,创建链表	
         L->next=Null;	
         scanf("%d",&x);  //输入要插入节点的数据	
         while(x!=-1)    //判断数据类型
         	{           s=(Node*)malloc(sizeof(Node));		
         	            s->date=x;		
         	            s->next=L->next;		
         	            L->next=s;		
         	            scanf("%d",&x);  //一次插入后,继续输入数据,循环
         	    }	
        return L;
   }	

(3)查找

①按序号查找结点

原理:单链表是一种顺序存取结构, 为找第 i 个数据元素, 必须从头顺序扫描前 i-1 个数据元素,需要计数器 j 与指针 p 协调处理。

算法思想:指针从头节点开始移动(指针位于头结点时J=0),当满足p->next!=null并且此时j

注意:从头节点开始j=0,1,2,3,元素与序号对应,便于处理。

算法实现:

 int  GetNode(Linklist L,int i)
 {    Node *p; int j;	
       if(i<0)	
           { 	print("查询位置不合法!");		
                 return Null;	
            }
       p=L;	
       j=0;		
       while((p->next!=Null)&&(j<i))
              {     p=p->next;		
         	       j++;	
              }	
        if(j==i)   //不满足while的第二个条件,跳出循环		
            return p;   //查找到结点	
        else        //不满足while的        
            return  Null;
    }
           

②按值

查找查找其值为key的结点,若找到则返回该结点的指针,否则返回NULL
算法实现:

    int  Locate(Linklist L,ElemType key)
            {	  Node *p;	
                  p=L->next;  //从第一个结点开始比较	
                  while(p!=Null)  //条件成立执行	
                       {	if(p->date!=key)			
                                      p=p->next;		
                                else			
                                         break;  //跳出循环体	
                         }	
                 return p;
             }

(4)删除结点

在链表中删除第 i 个结点同样需要找到并修改第 i-1 个结点的指针

int DelNode(Linklist L,int i)
{	Node *p *r;	
        p=Get(L,i-1);	
        if(!p||(p->next))       //p指针位置不存在;i结点指针位置不存在
              {        print ("删除位置不合法”);	  
                      return error;	
               }   
         r=p->next;	 
         p->next=r->next;    
        free(p);   //释放结点i空间	
        return ok; 
 }			 

注意:如果链表只有5个元素,删除第10个元素,则p不存在,位置不合法;删除第6个元素,p指针位置存在,但是p->next不存在,位置不合法,所以两种条件判断删除位置是否合法。

  1. 小练习
    (1)求链表的长度
int Length(Linklist L)
{	Node *p;int j;
	p=L;	j=0;	
	if(p->next!=Null)	
	     { 		j++;		
	            p=p->next;	
	      }	 
        return j;	 
         else		
	       return 0}

循环链表

1.什么是循环链表?
首尾相连的链表,即最后一个结点指针指向头节点或第一个结点。(也叫循环单链表)

数据结构C(一)——线性表的链式存储_第3张图片
2.操作,循环单链表的合并

已知:两个带头结点的循环单链表LA、LB,编写算法,将LA、LB合并为一个循环单链表,其头指针为LA。
算法思想:设置两循环链表的尾指针; 将第一条链表的尾指针指向第二条链表的第一个结点;将第二条链表的尾指针指向第一条链表的头指针;最后释放第二条链表的头指针,返回LA。
算法实现:
①带头指针的

Linklist  Link1(Linklist  LA,Linklist LB)
  {
          Node  *p,*q;
          p=LA;
          q=LB;
          while(p>next!=LA)  p=p->next;   //找到链表的尾指针
          while(q->next!=LB)  q=q->next;
          q->next=LA;   // LA=q->next;!!!错误的 LA地址覆盖q下一个指针指向的地址
          p->next=LB->next;
          free(LB);
          return(LA);

}
  
       

时间复杂度:O(m+n)

②带尾指针的
数据结构C(一)——线性表的链式存储_第4张图片


Linklist  Link2(Linklist RA,Linklist RB)
{
     Node *p;
     p=RA->next;
      RA->next=RB->next-next;
     free(RB->next);
     RB->next=p;
     return(RB);
}
        

   

时间复杂度O(1)

你可能感兴趣的:(数据结构)