简单链表

简单链表介绍

抽象数据类型 (Abstract Data Type,ADT)

ADT就是一个抽象的数据类型,类型包括两类信息:属性和操作。 现在要定义一个新的类型

  1. 是要提供储存结构的方法。
  2. 是要提供操作数据的法。
    简单来说,就是 要自己去定义一个新的类型,而且要对这个类型写一些可以操作的函数。

表ADT

整表创建

随机产生n个元素
void CreateListHead(LinkList *L,int n)
{
    LinkList p;
    int i;
    srand(time(0));
    *L=(LinkList)malloc(sizeof(Node));
    (*L)->next=NULL;
    for(i=0;i<n;i++)
    {
        p=(ListList)malloc(sizeof(Node));
        p->data=rand()%100+1;
        p->next=(*L)->next;
        (*L)->next=p;
    }
}

这里是头插法

顺序插入结点的步骤

随机产生n个元素
void CreateListHead(LinkList *L,int n)
{
    LinkList p,r;
    int i;
    srand(time(0));
    *L=(LinkList)malloc(sizeof(Node));
    r=*L;
    for(i=0;i<n;i++)
    {
        p = (ListList)malloc(sizeof(Node));
        p->data=rand()%100+1;
        r->next=p;
        r=p;
    }
    r->next=NULL;
}

删除链表中 datam 的元素。

struct ListNode *deletem( struct ListNode *L, int m )
{
    struct ListNode* record,*a;
    a=L;
    while(a)
    {   
        if(a->data==m)
        {
            if(a==L)
                L=a->next;
            else
                record->next=a->next;
        }
        else
        {
            record=a;
        }
        a=a->next;
    }
    return L;
}

删除整表

void Clear(LinkList *L)
{
    LinkList p,q;
    p=(*L)->next;
    while(p)
    {
        q=p->next;
        free(p);
        p=q;
    }
    (*L)->next=NULL;
}

链表的接口函数

无头结点

结构定义:

typedef struct LNode *PtrToLNode;
struct LNode 
{
    ElementType Data;
    PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;

接口函数:

Position Find( List L, ElementType X ) :返回线性表中首次出现X的位置。若找不到则返回ERROR;

List Insert( List L, ElementType X, Position P ) :将X插入在位置P指向的结点之前,返回链表的表头。如果参数P指向非法位置,则打印“Wrong Position for Insertion”,返回ERROR;

List Delete( List L, Position P ) :将位置P的元素删除并返回链表的表头。若参数P指向非法位置,则打印“ Wrong Position for Deletion ”并返回ERROR。

Position Find( List L, ElementType X )
{
    List p=L;
    while(p&&p->Data!=X)
    {
        p=p->Next;
    }
    if(p!=NULL)
        return p;
    else
        return ERROR;
}
List Insert(List L,ElementType X,Position P)
{
   List temp,p;
   if(P==L)//如果要插向第一个结点之前
   {
      temp=(List)malloc(sizeof(struct LNode));
      temp->Data=X;
      temp->Next=L;//新结点的next指向现在的第一个结点,所以第一个结点现在变成了temp
      L=temp;
      return L;//返回第一个
   }
   temp=L;
   while(temp)
   {
      if(temp->Next==P)//如果下一个为P,即 要将新结点插入temp与P之间
      {
         p=(List)malloc(sizeof(struct LNode));
         p->Data=X;
         p->Next=temp->Next;//要插入的结点的next指向P
         temp->Next=p;//要插入的结点的前一个结点的next指向插入的结点
         return L;
      }
      temp=temp->Next;
   }
   printf("Wrong Position for Insertion\n");
   return ERROR;
}
List Delete(List L,Position P)
{
   List p=L;
   if(P==L)
   {
      L=L->Next;
      return L;
   }
   while(p)
   {
      if(p->Next==P)
      {
         p->Next=P->Next;
         free(P);
         return L;
      }
      p=p->Next;
   }
   printf("Wrong Position for Deletion\n");
   return ERROR;
}

有头结点

结构定义:

typedef struct LNode *PtrToLNode;
struct LNode {
    ElementType Data;
    PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;

接口函数

List MakeEmpty() :创建并返回一个空的线性表;

Position Find( List L, ElementType X ) :返回线性表中X的位置。若找不到则返回ERROR;

bool Insert( List L, ElementType X, Position P ) :将X插入在位置P指向的结点之前,返回true。如果参数P指向非法位置,则打印“Wrong Position for Insertion”,返回false;

bool Delete( List L, Position P ) :将位置P的元素删除并返回true。若参数P指向非法位置,则打印“ Wrong Position for Deletion ”并返回false。

List MakeEmpty()
{
    List head=(List)malloc(sizeof(struct LNode));
    head->Data=0;
    head->Next=NULL;//头指针指向空
    return head;
}
Position Find( List L, ElementType X )
{
    List F=L;
    while(F)//每个头结点判断,直到其为空
    {
        if(F->Data==X)
        {
            return F;//如果找到返回F的位置
        }
        F=F->Next;
    }
    return ERROR;//F为空也没有找到,就返回ERROR
}
bool Insert( List L, ElementType X, Position P )
{
    List F=L;
    while(F)
    {
        if(F->Next==P)//这时F是P的前一个结点
        {
            List p=(List)malloc(sizeof(struct LNode));
            p->Data=X;
            p->Next=P;//P的Next指向P
            F->Next=p;//F的Next指向p
            return true;
        }
        F=F->Next;
    }
    printf("Wrong Position for Insertion\n");
    return false;//如果没有找到就返回
}
bool Delete( List L, Position P )
{
    List F=L;
    if(!P)//要删的如果是空
    {
        printf("Wrong Position for Deletion\n");
        return false;
    }
    while(F)
    {
        if(F->Next==P)找到P,F为其前一个结点
        {
            F->Next=P->Next;//F的Next指针指向P的Next
            free(P);//释放P
            return true;
        }
        F=F->Next;
    }
    printf("Wrong Position for Deletion\n");
    return false;//没找到返回
}

可以看到每一个函数都用到了 while(F) 这样的形式来判断循环,但是要注意的是,如果判断到 NLULL 会跳出,不要在循环体外再用 F->Next 如果 F 已经为空,那么 F->Next 会出现段错误,找不到这个地址。

顺序表

结构定义:

typedef int Position;
typedef struct LNode *List;
struct LNode 
{
    ElementType Data[MAXSIZE];
    Position Last; /* 保存线性表中最后一个元素的位置 */
};

接口函数:

List MakeEmpty() :创建并返回一个空的线性表;

Position Find( List L, ElementType X ) :返回线性表中X的位置。若找不到则返回ERROR;

bool Insert( List L, ElementType X, Position P ) :将X插入在位置P并返回true。若空间已满,则打印“FULL”并返回false;如果参数P指向非法位置,则打印“ ILLEGAL POSITION ”并返回false;

bool Delete( List L, Position P ) :将位置P的元素删除并返回true。若参数P指向非法位置,则打印“ POSITION P EMPTY ”(其中P是参数值)并返回false。

bool Insert( List L, ElementType X, Position P )                               
{   
    if(L->Last+1==MAXSIZE)                                                     
    {   
        printf("FULL");                                                        
        return false;                                                          
    }
    if(P>L->Last+1||P<0)                                                       
    {   
        printf("ILLEGAL POSITION");                                            
        return false;                                                          
    }
    for(int i=L->Last;i>=P;i--)                                                
    {   
        L->Data[i+1]=L->Data[i];                                               
    }
    L->Data[P]=X;                                                              
    L->Last++;
    return true;                                                               
}
bool Delete( List L, Position P )                                              
{   
    if(P>L->Last||P<0)                                                         
    {   
        printf("POSITION %d EMPTY",P);                                         
        return false;                                                          
    }
    for(int i=P;i<=L->Last;i++)                                                
    {   
        L->Data[i]=L->Data[i+1];                                               
    }
    L->Last--;
    return true;                                                               
}                            
List MakeEmpty()
{
    List head=(List)malloc(sizeof(struct LNode));
    head->Last=-1;
    return head;
}
Position Find( List L, ElementType X )
{
    for(int i=0;i<=L->Last;i++)
    {
        if(L->Data[i]==X)                                                      
            return i;
    }
    return ERROR;
}

静态链表

原理

因为不是所有语言都有指针,所以 可以用数组的形式来模拟指针。叫游标实现。

  1. 数组下标为0,也就是第一个元素。这其中有一个值来记录一个空位。
  2. 数组的最后一个元素中的一个值记录最初的那个插入元素的位置。它就相当于头指针。

所以初始是这样

结构定义

#define MAXSIZE 1000
typedef struct 
{
    ElemType data;
    int cur;
}Component,StaticLinkList[MAXSIZE];

接口定义

//初始化
Status InitList(StaticLinkList space)
{
    int i;
    for(i=0;i<MAXSIZE-1;i++)
    {
        space[i].cur=i+1;
    }
    space[i].cur=0;
    reutrn OK;
}
//找到空闲区
int Malloc_SLL(StaticLinkList space)
{
    int i=space[0].cur;//找到原先的空闲位置
    if(space[0].cur)
        space[0].cur=space[i].cur;//这个空闲要被用了,请把这个空闲的下一个给 的第0个元素的cur,以标志着它成为了第一个空闲。

    return i;//返回这个空闲的位置
}
//在L中第i个元素之前插入元素e
Status ListInsert(StaticLinkList L,int i,Elemtype e)
{
    int j,k,l;
    k=MAXSZIE-1;
    if(i<L||i>ListLength(L)+1)
        return ERROR;
    j=MALLOC_SLL(L);//获得空闲下标
    if(j)
    {
        L[j].data=e;
        for(l=1;l<=i-1;i++)/*找到第i个元素之前的位置,第一个元素就是0,第二个元素就是1。k本身记录1的位置。循环一次得到第二个元素,循环两次是第三个元素,以此类推。*/
            k=L[k].cur;//遍历
        L[j].cur=L[k].cur;//新元素的下一个是第i个元素
        L[k].cur=j;//第i个元素之前的元素的下一个是新元素
        return OK;
    }
    return ERROR;
}

将丙插入后就是这样


用上面的代码解释就是,要将丙插入第三个位置之前,先找到空闲位置赋值丙,循环两次找到乙,把乙的下一个位置给空闲的下一个位置,空闲位置给乙的下一个位置。

删除

Status ListDelete(StaticLinkList L,int i)
{
    int j,k;
    if(i<1||i>ListLength(L))
        return ERROR;
    k=MAXSIZE-1;
    for(j=1;j<=i-1;j++>)
        k=L[k].cur;//找到前一个
    j=L[k].cur;//找到要删的
    L[k].cur=L[j].cur;//将要删的下一个给前一个的下一个
    Free_SSL(L,j);
    return OK:
}
void Free_SSL(StaticLinkList space,int k)
{
    space[k].cur=space[0].cur;//k的下一个为空闲位置
    space[0].cur=k;//k作为新的空闲位置
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

CCPigSnail

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

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

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

打赏作者

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

抵扣说明:

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

余额充值