算法入门-----刷爆链表

目录

前言

一、实战

1.创建链表

 2.创建链表

尾插法

 头插法

 3.遍历链表

 4.查找元素

按照位置查找

按值查找

5.插入元素 

6.删除结点

7.完整menu 

总结


前言

在刚开始进行算法刷题时,一定会遇到一个重要知识点——链表,主要是基于指针和结构体的应用,本博客整理了近期博主记录的链表基本操作,先打牢基础再开始刷题才会更流畅哦!

一、实战

基于c语言实现对链表的基本操作

1.创建链表

链表创建时要注意创建储存结点的结点域,用于指向结点便于后续增删改查操作

// 定义链表节点
typedef struct LNode {
    int data;           // 数据域
    struct LNode* next; // 指针域
} LNode, * Linklist;

 初学者误区:

Linklist L:定义的是指向链表的z指针,链表中定义了数据和指针

lNode l:定义的是指向结点的指针,是链表的一部分

 2.创建链表

尾插法

创建链表与后续插入元素的代码相关性很强

// 创建链表(尾插法)
Linklist creat(Linklist L) {
    int x;//用于输入数值
    LNode* s, * r; // s为新节点,r为尾节点
    L = (LNode*)malloc(sizeof(LNode)); // 为头节点申请空间
    L->next = NULL; // 初始为空链表,避免为野指针
    r = L; // 尾指针指向头节点
    printf("请输入数据,以-1结束:\n");
    scanf("%d", &x);
    while (x != -1) {
        s = (LNode*)malloc(sizeof(LNode)); // 创建新节点
        s->data = x; // 赋值
        r->next = s; // 尾节点指向新节点
        r = s; // 尾指针移动到新节点
        scanf("%d", &x); // 读取下一个数据
    }
    r->next = NULL; // 尾节点指向NULL
    return L;
}

 头插法

// 创建链表(头插法)
Linklist creat(Linklist L) {
    int x;
    LNode* s; // s为新节点,r为尾节点
    L = (LNode*)malloc(sizeof(LNode)); // 头节点
    L->next = NULL; // 初始为空链表
    printf("请输入数据,以-1结束:\n");
    scanf("%d", &x);
    while (x != -1) {
        s = (LNode*)malloc(sizeof(LNode)); // 创建新节点
        s->data = x; // 赋值
        s->next = L->next; //先找到头结点的下一个元素
        L->next = s; //头结点前移
        scanf("%d", &x); // 读取下一个数据
    }
    return L;
}

 3.遍历链表

链表的第一个结点为L->next,并不是L所指的默认第一个结点,第一个结点为空

// 遍历链表
void trave(Linklist L) {
    LNode* p = L->next; // 头节点指向的第一个节点
    while (p) {
        printf("%d\t", p->data); // 打印节点数据
        p = p->next; // 指针后移
    }
    printf("\n");
}

 4.查找元素

按照位置查找

返回所指位置结点的指针,再由p->data获取该位置数据值

// 获取第i个节点的指针
LNode* getelem(Linklist L, int i) {
    if (i < 0) return NULL; // 非法位置
    LNode* p = L;
    int j = 0;
    while (p && j < i) {
        p = p->next;
        j++;
    }
    return p;
}

按值查找

// 按值查找,返回位置
int locate(Linklist L, int e) {
    LNode* p = L->next;//指向第一个结点
    int pos = 1;//用于计算位置
    while (p && p->data != e) {
        p = p->next;
        pos++;
    }
    if (p == NULL) return 0; // 没找到目标元素
    return pos;
}

5.插入元素 

// 在第i个位置插入元素e
int insert(Linklist L) {
    int i, e;
    printf("请输入要插入的位置和数据:\n");
    scanf("%d %d", &i, &e);
    if (i < 1) return 0; // 非法位置
    LNode* p = getelem(L, i - 1); // 获取第i个节点的前一个节点
    if (!p) return 0; // 非法位置
    LNode* s = (LNode*)malloc(sizeof(LNode)); // 创建新节点
    if (!s) return 0; // 内存分配失败
    s->data = e; // 赋值
    s->next = p->next; // 新节点指向原来i位置的节点
    p->next = s; // 前一个节点指向新节点
    return 1;
}

6.删除结点

删除结点是也是先找到目标结点下一个结点

// 删除第i个位置的元素
int delete(Linklist L) {
    int i;
    printf("请输入要删除的位置:\n");
    scanf("%d", &i);
    if (i < 1) return 0; // 非法位置
    LNode* p = getelem(L, i - 1); // 获取第i个节点的前一个节点
    if (!p || !(p->next)) return 0; // 非法位置,或者没有下一个节点
    LNode* q = p->next; // 待删除的节点
    p->next = q->next; // 前一个节点指向下下个节点
    free(q); // 释放内存
    return 1;
}

7.完整menu 

将上述操作整合到一个链表小程序里面,就可以进行实时操作选择啦~

#include <stdio.h>
#include <stdlib.h>

// 定义链表节点
typedef struct LNode {
    int data;           // 数据域
    struct LNode* next; // 指针域
} LNode, * Linklist;

// 创建链表(尾插法)
Linklist creat(Linklist L) {
    int x;
    LNode* s, * r; // s为新节点,r为尾节点
    L = (LNode*)malloc(sizeof(LNode)); // 头节点
    L->next = NULL; // 初始为空链表
    r = L; // 尾指针指向头节点
    printf("请输入数据,以-1结束:\n");
    scanf("%d", &x);
    while (x != -1) {
        s = (LNode*)malloc(sizeof(LNode)); // 创建新节点
        s->data = x; // 赋值
        r->next = s; // 尾节点指向新节点
        r = s; // 尾指针移动到新节点
        scanf("%d", &x); // 读取下一个数据
    }
    r->next = NULL; // 尾节点指向NULL
    return L;
}

// 遍历链表
void trave(Linklist L) {
    LNode* p = L->next; // 头节点指向的第一个节点
    while (p) {
        printf("%d\t", p->data); // 打印节点数据
        p = p->next; // 指针后移
    }
    printf("\n");
}

// 获取第i个节点的指针
LNode* getelem(Linklist L, int i) {
    if (i < 0) return NULL; // 非法位置
    LNode* p = L;
    int j = 0;
    while (p && j < i) {
        p = p->next;
        j++;
    }
    return p;
}

// 按值查找,返回位置
int locate(Linklist L, int e) {
    LNode* p = L->next;
    int pos = 1;
    while (p && p->data != e) {
        p = p->next;
        pos++;
    }
    if (p == NULL) return 0; // 没找到目标元素
    return pos;
}

// 在第i个位置插入元素e
int insert(Linklist L) {
    int i, e;
    printf("请输入要插入的位置和数据:\n");
    scanf("%d %d", &i, &e);
    if (i < 1) return 0; // 非法位置
    LNode* p = getelem(L, i - 1); // 获取第i个节点的前一个节点
    if (!p) return 0; // 非法位置
    LNode* s = (LNode*)malloc(sizeof(LNode)); // 创建新节点
    if (!s) return 0; // 内存分配失败
    s->data = e; // 赋值
    s->next = p->next; // 新节点指向原来i位置的节点
    p->next = s; // 前一个节点指向新节点
    return 1;
}

// 删除第i个位置的元素
int delete(Linklist L) {
    int i;
    printf("请输入要删除的位置:\n");
    scanf("%d", &i);
    if (i < 1) return 0; // 非法位置
    LNode* p = getelem(L, i - 1); // 获取第i个节点的前一个节点
    if (!p || !(p->next)) return 0; // 非法位置,或者没有下一个节点
    LNode* q = p->next; // 待删除的节点
    p->next = q->next; // 前一个节点指向下下个节点
    free(q); // 释放内存
    return 1;
}

int main() {
    Linklist L = NULL;
    int num;
    while (1) {
        printf("\n*******0.退出 1.创建链表 2.遍历链表 3.插入元素 4.删除元素 5.获取元素 6.查找元素*******\n");
        printf("请选择操作:");
        scanf("%d", &num);
        switch (num) {
        case 0:
            printf("退出程序。\n");
            return 0;
        case 1:
            L = creat(L);
            printf("链表创建成功。\n");
            break;
        case 2:
            if (L) {
                printf("链表元素:");
                trave(L);
            }
            else {
                printf("链表为空,请先创建链表。\n");
            }
            break;
        case 3:
            if (L) {
                if (insert(L))
                    printf("插入成功。\n");
                else
                    printf("插入失败。\n");
            }
            else {
                printf("链表为空,请先创建链表。\n");
            }
            break;
        case 4:
            if (L) {
                if (delete(L))
                    printf("删除成功。\n");
                else
                    printf("删除失败。\n");
            }
            else {
                printf("链表为空,请先创建链表。\n");
            }
            break;
        case 5: {
            int i;
            printf("请输入要获取的元素位置:");
            scanf("%d", &i);
            LNode* node = getelem(L, i);
            if (node)
                printf("位置 %d 上的元素为 %d。\n", i, node->data);
            else
                printf("位置 %d 无效。\n", i);
            break;
        }
        case 6: {
            int e;
            printf("请输入要查找的元素:");
            scanf("%d", &e);
            int pos = locate(L, e);
            if (pos)
                printf("元素 %d 在链表中的位置为 %d。\n", e, pos);
            else
                printf("元素 %d 未找到。\n", e);
            break;
        }
        default:
            printf("无效的选项,请重新选择。\n");
        }
    }
    return 0;
}


总结

链表的一系列操作在逻辑上看是非常简单的,但是实际写代码操作时会遇到许多问题,快来敲爆键盘and刷爆leetcode吧!just go for it,希望可以帮助到学习链表或者指针和结构体的你!

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值