1.单链表定义

每个节点包括一个数据域一个指针域,节点在内存中地址可以不连续,但是节点内部地址必然连续。
图片描述

2.结构定义

typedef struct Lnode{
int data;
struct Lnode *next;
}Lnode,*LinkList;

3.单链表的创建

1)头插法
每次将s指向节点放在最前面,所以与输入顺序相反,先找到下一节点再解链

//头插法建立带头结点的单链表
LinkList create1(LinkList &L){
  Lnode *s;
  int x; 
  L=(LinkList) malloc( sizeof(Lnode));//创建头结点
  L->next = NULL; //初始化
  printf("往链表中添加数据,99999结束\n");
  scanf("%",&x);
  while(x!=99999){
      s = (Lnode*)malloc(sizeof(Lnode));//创建新节点
      s->data = x;
      s->next = L->next;
      L->next = s;
      scanf("%d",&x);
       
  }


return L;
}

2)尾插法
每次插入节点都在链表最后,所以与输入顺序相同,不用先解链,只用把尾指针不断指向新的表尾节点

//尾插法建立单链表
LinkList create2(LinkList &L){

    int x;
    L=(LinkList) malloc( sizeof(Lnode));//创建尾结点
    Lnode *s,*r = L;//S为插入节点指针,r为尾指针
printf("往链表中添加数据,99999结束\n");
    //scanf("%",&x);
    while(x!=99999){
      s = (Lnode*)malloc(sizeof(Lnode));//创建新节点
      scanf("%d",&x); 
      s->data = x;
      r->next = s;
      r = s; //r指向新的表尾
      
    }
    r->next = NULL;//尾节点指针置空
    return L;
}

4.单链表的查找

1)按值查找

//按值查找表节点,返回节点位序,查找失败返回-1
int locateElem(LinkList L, int e){
    Lnode *P = L->next;
    int j=1;
    while (P!=NULL&&P->data!=e){
      P = P->next;
      j++;
    }
     if(P->next == NULL && P->data == e)
    return j;
    else if(P->next != NULL && P->data == e)
    return j;
    else
        return -1;
}
//按值查找表节点,返回节点指针,这是方便链表运算实现
Lnode *locateElem2(LinkList L, int e){
 Lnode *P = L->next;
    while (P!=NULL&&P->data!=e){
      P = P->next;
    }
    return P;//失败则返回空指针
}

2)按序号查找

//按序号查找表节点,返回节点值
int getElem(LinkList L,int i){
    int j = 1;
    Lnode *P = L->next;
    if(i==0)
        return 0;//如果i=0,则返回头结点的值,但头结点不存值故返回0
    if(i<0)
        return -1;//错误序号则返回-1
    while(P&&j<i)//P非空
    {
       P= P->next;
       j++;
    }
   return P->data;
}

//按序号查找表节点,返回节点指针,这是方便链表运算实现
Lnode *getElem1(LinkList L, int i){
   int j = 1;
    Lnode *P = L->next;
    if(i==0)
        return L;//如果i=0,则返回头结点
    if(i<0)
        return NULL;//错误序号则返回NULL
    while(P&&j<i)//P非空
    {
       P= P->next;
       j++;
    }
   return P;
}


4.单链表表长

int getLength(LinkList L){
   int count = 0;
   while(L->next->next!=NULL)//此处指针因人而异,思想就是尾节点指针为空结束循环
   {
       L = L->next;
    count ++;
   }
   return count;
}

5.插入节点

//插入节点算法1(后插,前插一般不考虑)
//指定位置插入节点
int insertElem1(LinkList L,int i,int e){
    if (i<=1||i>getLength(L))
    {
    return 0;
    }
    else
    {
   Lnode *s,*p;
   p = getElem1(L,i-1);//获取插入位置前驱
   s = (Lnode*)malloc(sizeof(Lnode));//创建新节点
   s->data = e;
   s->next = p->next;//此句和下面那句代码不可颠倒,单链表只可找到后继,所以后继指针不能被先覆盖
   p->next = s;
   return 1;
    }
}

//插入节点算法2
//只交换数据,不改变指针,在已知节点位置的基础上这个是最优算法
int insertElem2(LinkList L,int i,int e){
    int temp;
    if (i<=1||i>getLength(L))
    {
    return 0;
    }
    else
    {
   Lnode *s,*p;
   p = getElem1(L,i);//获取插入位置前驱
   s = (Lnode*)malloc(sizeof(Lnode));//创建新节点
   s->data = e;
   s->next = p->next;
   p ->next = s;
    temp = p->data;//这里做个数据交换
   p->data = s->data;
   s->data = temp;  
   return 1;
    }
}

6.完整代码

#include <stdio.h>
#include <stdlib.h>//malloc函数头文件
//单链表定义
typedef struct Lnode{

int data;
struct Lnode *next;
}Lnode,*LinkList;

//头插法建立带头结点的单链表
LinkList create1(LinkList &L){
  Lnode *s;
  int x; 
  L=(LinkList) malloc( sizeof(Lnode));//创建头结点
  L->next = NULL; //初始化
  printf("往链表中添加数据,99999结束\n");
  scanf("%",&x);
  while(x!=99999){
      s = (Lnode*)malloc(sizeof(Lnode));//创建新节点
      s->data = x;
      s->next = L->next;
      L->next = s;
      scanf("%d",&x);
       
  }


return L;
}
  //尾插法建立单链表
LinkList create2(LinkList &L){

    int x;
    L=(LinkList) malloc( sizeof(Lnode));//创建尾结点
    Lnode *s,*r = L;//S为插入节点指针,r为尾指针
printf("往链表中添加数据,99999结束\n");
    //scanf("%",&x);
    while(x!=99999){
      s = (Lnode*)malloc(sizeof(Lnode));//创建新节点
      scanf("%d",&x); 
      s->data = x;
      r->next = s;
      r = s; //r指向新的表尾
      
    }
    r->next = NULL;//尾节点指针置空
    return L;
}

//求单链表表长
int getLength(LinkList L){
   int count = 0;
   while(L->next->next!=NULL)
   {
       L = L->next;
    count ++;
   }
   return count;
}
//按序号查找表节点,返回节点值
int getElem(LinkList L,int i){
    int j = 1;
    Lnode *P = L->next;
    if(i==0)
        return 0;//如果i=0,则返回头结点的值,但头结点不存值故返回0
    if(i<0)
        return -1;//错误序号则返回-1
    while(P&&j<i)//P非空
    {
       P= P->next;
       j++;
    }
   return P->data;
}

//按序号查找表节点,返回节点指针,这是方便链表运算实现
Lnode *getElem1(LinkList L, int i){
   int j = 1;
    Lnode *P = L->next;
    if(i==0)
        return L;//如果i=0,则返回头结点
    if(i<0)
        return NULL;//错误序号则返回NULL
    while(P&&j<i)//P非空
    {
       P= P->next;
       j++;
    }
   return P;
}

//按值查找表节点,返回节点位序,查找失败返回-1
int locateElem(LinkList L, int e){
    Lnode *P = L->next;
    int j=1;
    while (P!=NULL&&P->data!=e){
      P = P->next;
      j++;
    }
     if(P->next == NULL && P->data == e)
    return j;
    else if(P->next != NULL && P->data == e)
    return j;
    else
        return -1;
}
//按值查找表节点,返回节点指针,这是方便链表运算实现
Lnode *locateElem2(LinkList L, int e){
 Lnode *P = L->next;
    while (P!=NULL&&P->data!=e){
      P = P->next;
    }
    return P;//失败则返回空指针
}

//插入节点算法1(后插,前插一般不考虑)
//指定位置插入节点
int insertElem1(LinkList L,int i,int e){
    if (i<=1||i>getLength(L))
    {
    return 0;
    }
    else
    {
   Lnode *s,*p;
   p = getElem1(L,i-1);//获取插入位置前驱
   s = (Lnode*)malloc(sizeof(Lnode));//创建新节点
   s->data = e;
   s->next = p->next;//此句和下面那句代码不可颠倒,单链表只可找到后继,所以后继指针不能被先覆盖
   p->next = s;
   return 1;
    }
}

//插入节点算法2
//只交换数据,不改变指针,在已知节点位置的基础上这个是最优算法
int insertElem2(LinkList L,int i,int e){
    int temp;
    if (i<=1||i>getLength(L))
    {
    return 0;
    }
    else
    {
   Lnode *s,*p;
   p = getElem1(L,i);//获取插入位置前驱
   s = (Lnode*)malloc(sizeof(Lnode));//创建新节点
   s->data = e;
   s->next = p->next;
   p ->next = s;
    temp = p->data;//这里做个数据交换
   p->data = s->data;
   s->data = temp;  
   return 1;
    }
}


int main(){
    LinkList L,L1;
    /*
    create1(L);
     LinkList temp = L->next;
    while(temp->next != NULL)
    {
        printf("%d ", temp->data);
        temp = temp->next;
    }
    printf("头插法与存数据的顺序相反\n");
*/
    create2(L1);
    LinkList temp2 = L1->next;
     while(temp2 ->next != NULL)
    {
        printf("%d ", temp2->data);
        temp2 = temp2->next;
    }
    printf("尾插法与存数据的顺序相同\n");
    int length;
    length = getLength(L1);
    printf("单链表长度为:%d\n",length);
    /*
     printf("输入取值位序\n");
     int i;
      scanf("%d",&i);
      printf("第%d位值为%d\n",i, getElem(L1,i));

      printf("输入查找值\n");
     int e;
      scanf("%d",&e);
      printf("值为:%d位序为:%d\n",e, locateElem(L1,e));
      */
      //插入节点算法1
      /*
      int x1,x2;
       printf("插入节点算法1\n");
       printf("插入位置:");
        scanf("%d",&x1);
        printf("插入值:");
        scanf("%d",&x2);
        int desert = insertElem1(L1,x1,x2);
        if(desert == 1)
        {
           printf("插入成功\n");
           LinkList temp3 = L1->next;
        }
        else
        {
            printf("插入失败,位置不合法\n");
        }
         printf("打印链表(插入算法1)\n");
         LinkList temp3 = L1->next;
     while(temp3 ->next != NULL)
    {
        printf("%d ", temp3->data);
        temp3 = temp3->next;
    }
*/
      //插入节点算法2
      int x3,x4;
       printf("插入节点算法2\n");
       printf("插入位置:");
        scanf("%d",&x3);
        printf("插入值:");
        scanf("%d",&x4);
        int desert1 = insertElem2(L1,x3,x4);
        if(desert1 == 1)
        {
           printf("插入成功\n");
           LinkList temp4 = L1->next;
        }
        else
        {
         printf("插入失败,位置不合法\n");
        }
         printf("打印链表(插入算法2)\n");
         LinkList temp4 = L1->next;
     while(temp4 ->next != NULL)
    {
        printf("%d ", temp4->data);
        temp4 = temp4->next;
    }
return 0;
}

7.小结

单链表作为链表中最简单的一种,摆脱了顺序表对空间的束缚,可以很好的支持动态操作。但是其问题也很明显,每个节点只能找到其直接后继,而找不到其前一节点。在查找时需要从表头开始遍历表,会增加时间复杂度。


邓琳平
59 声望11 粉丝

这个人很懒