链表

139 阅读4分钟

一、链表特点

  • 储存多种数据类型类型
  • 可根据需要动态分配存储空间
  • 数组移动中,要对元素进行大范围的移动,耗时间,效率低

二、链表构成

  • 链表由一个头指针和若干个节点组成,最后一个节点指向空
  • 实现原理:头指针指向链表的第一个节点,第一个节点的指针指向下一个节点,然后依次指到最后一个节点
  • 链表的数据结构
struct list_node{
    int data;//用于存储数据
    struct list_node *next;//指针,可以用来访问节点数据,也可以遍历,指向下一个节点
};
  • 节点的创建
typedef struct list_node{
    int data;
    struct list_node *next;
}list_single;

list_single *create_list_node(int data){//将节点封装为一个函数
    list_single *node = NULL;//定义头指针
    node = (list_single *)malloc(sizeof(list_single));//分配内存
    if (node = NULL){
        printf("malloc fair!\n");
    }
    memset(node,0, sizeof(list_single));//清内存
    node->data = data;
    node->next = NULL;
    return node;
}
  • 单链表的尾插
    只需实现header->next = new;即使当前指向新的节点
  • 单链表的头插
    即把新的节点插在两个节点之间 只需实现
    now_up->next = new;
    new->next = now_down;
  • 单链表的遍历 需要注意:
    不需要打印头节点
    判断节点是否到达了稳健点
    流程
    (1)获取当前节点位置,访问头节点
    struct list *p = header; (2)使头节点指向下一个节点 p = p->next;
    (3)判断是否为最后一个节点
    如果不是 先打印第一个节点的数据 然后移到下一个节点 重复这两个步骤
    如果是 直接打印数据
printf("%d",p->data);     
while(p->next != NULL){
    p = p->next;

}

  • 删除节点流程
    (1)先定义两个指针,一个表示当前节点,另一个表示当前节点的上一个节点
struct list *p = header;     
struct list *prev = NULL;   

(2)遍历整个链表,同时保存当前节点的前一个节点

while(p->next != NULL){        
    prev = p;//保存当前节点的前一个节点      
    p = p->next;//保存当前偏移的节点     
    return 0;

} (3)在遍历的过程中查找要删除的数据

while(p->next != NULL){
    prev = p;
    p = p->next;
    if(p->id == data)//查找数据
    {
       prev->next = p->next;//使前一个节点的指向取代当前节点的指向
    }
    free(p);
    
}
  • 实操 (1)不可增加删减
#include <stdio.h>
#include <string.h>

struct student{
    char name[10];
    struct student *next;
};

struct student *create(){
    struct student *head,*current,*next;
    char flag;
    char str[10];

    printf("输入姓名:\n");
    scanf("%s",str);
    head = malloc((struct student *) sizeof(struct student));
    strcpy(head->name,str);
    current = head;//将当前指针赋给current
    printf("是否继续输入\n");//Y or N
    scanf ("%s",&flag);

    while (flag != 'N')
    {
        printf("输入姓名:\n");
        scanf("%s",str);
        next = malloc((struct student *) sizeof(struct student));
        strcpy (next->name,str);
        current->next = next;//将next指针赋给当前指针
        printf("是否继续输入");//Y or N
        scanf ("%s",&flag);
    }
    return head;//返回结构体指针
}

int main(){
    struct student *p;
    p = create();

    while (1){
        printf("%s\n",p->name);
        if(p->next != NULL){
            p = p->next;//使指针p指向下一个指针
        } else
        {
            break;
        }
    }
}



//可增加删减
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct slist{
    int id;
    struct slist *next;
}L;

L *create_node(int data){//创建一个节点
    L *p = malloc(sizeof(L));//给每个节点分配结构体一样的空间大小
    if(p == NULL){
        printf("malloc error\n");
        return NULL;
    }
    memset(p,0, sizeof(L));//清内存
    p->id = data;
    p->next = NULL;

}
void tail_insert(L *pH,L *new){//链表的尾插
    L *p = pH;//获取当前位置
    while (p->next != NULL){
        p = p->next;//移动到下一个节点
    }
    p->next = new;

}

void top_insert(L *pH,L *new){//链表的头插
    L *p = pH;
    new->next = p->next;
    p->next = new;
}

void Print_node(L *pH){//遍链表历
    L *p = pH;
    p = p->next;
    while (p->next != NULL){
        printf("id = %d\n",p->id);
        p = p->next;
    }
    printf("id = %d\n",p->id);
}
int delete_list_node(L *pH,int data){
    L *p = pH;//获取当前头节点的文职
    L *prev = NULL;
    while (p->next != NULL){
        prev = p;//保存当前节点的前一个节点的指针
        p = p->next;//让当前的指针继续往后移动
        if(p->id == data){
            if(p->next !=NULL){//普通节点删除
                prev->next = p->next;
                free(p);
            } else{//尾节点删除
                prev->next = NULL;
                free(p);
            }
            return 0;
        }
    }
    printf("没有要删除的节点\n");
    return -1;
}
void trave_list(L *pH){
    L *p = pH->next;//保存第一个节点的位置
    L *pBack;
    int i =0;
    if(p->next == NULL || p == NULL)
        return;
    while (p->next != NULL){//遍历链表
        pBack = p->next;//保存第一个节点的下一个节点
        //找到第一个有效节点,其实就是头指针的下一个节点
        if(p == pH->next){
            p->next = NULL;//第一个有效节点就是最后一个及诶点,所以要指向NULL;
        } else{
            p->next = pH->next;//尾部链接
        }
        pH->next = p;//头部链接
        p = pBack;//走下一个节点

    }
    top_insert(pH,p);//插入最后一个节点
}

int main(){
    int i;
    L *header = create_node(0);
    for (i = 0;i<10;i++){
        tail_insert(header,create_node(i));
    }
    Print_node(header);
    delete_list_node(header,5);
    putchar('\n');
    Print_node(header);
    putchar('\n');
    trave_list(header);
    Print_node(header);
    return 0;
}

参考:bilibili
未完待续