数据结构基础——单链表

关于单链表的一些基本操作,以下为基本思路代码

首先看一张直观图
直观图

链表的结构体定义如下(为简便,这里的ElemType采用int):

//单链表
typedef struct LNode {
    int data;
    struct LNode *next;
} LinkList;

接下来肯定就是建立链表,而目前建立单链表分为两种方式,分别是"头插法"与"尾插法",首先看图示:
头插法

尾插法

清楚明白:

  • 头插法就是每次插入的节点在上一个节点之前,头节点之后
  • 尾插法就是每次插入的节点在上一节点之后

我们对比来看节点的插入:

//头插法核心代码
s = (LinkList *) malloc(sizeof(LinkList));
s->data = a[i];
s->next = L->next;//将s插入到下一节点之前
L->next = s;  

//尾插法核心代码
s = (LinkList *) malloc(sizeof(LinkList));
s->data = a[i];
r->next = s;//将s插入到r之后
 r = s;

那么写成函数,就是如下所示:

/**
 * 头插法建立单链表
 * @param a 数组元素,对应data
 * @param n 链表长度(除去头结点)
 */
void CreateListByHead(LinkList *L, const int a[], int n) {
    LinkList *s;
    //建立头节点
    L->next = NULL;
    for (int i = 0; i < n; ++i) {
        s = (LinkList *) malloc(sizeof(LinkList));
        s->data = a[i];
        s->next = L->next;//将s插入到下一节点之前
        L->next = s;
    }
}

/**
 * 尾插法建立单链表
 * @param a 数组元素,对应data
 * @param n 链表长度(除去头结点)
 */
void CreateListByTail(LinkList *L, const int a[], int n) {
    LinkList *r = L, *s;
    for (int i = 0; i < n; ++i) {//循环建立数据节点
        s = (LinkList *) malloc(sizeof(LinkList));
        s->data = a[i];
        r->next = s;//将s插入到r之后
        r = s;
    }
    r->next = NULL; //尾节点next域置为空
}

那么接下来的集中基本操作方法也就不再赘述,其实都是一些对链表的操作,指针的移动,临界条件的判断,我也都写在注释中了,尤其是第一个Delete方法写的最详细,可以仔细看一下哦,为了直观一点,我也附上代码图片(编译环境Clion)~

按照逻辑序号删除某节点

这里也要注意是否会断链的问题,free()不要释放错了,否则会有错误
删除操作

直观代码

/**
 * 删除单链表中的第i个元素
 * @param L 链表
 * @param i 第i个元素
 * @return  程序执行完毕状态
 */
int ListDelete(LinkList *L, int i) {
    int j = 0;
    LinkList *p = L, *q;
    /*
     *找到第i-1个节点 ,p!= NULL 是防止寻找的节点超过链表,
     * 比如一共有四个节点,而i=6即想找到第6个节点,那么当j++变成5,
     * p指向第五个不存在的节点后就会返回NULL
     *此时循环结束,p == NULL
     */
    while (j < i - 1 && p != NULL) {
        j++;
        p = p->next;
    }
    if (p == NULL)
        return ERROR;
    else {
        q = p->next;
        /*
         * 如果p->next为空,则返回ERROR
         * 此时是为了防止边界条件的情况
         *  若链表一共有四个节点,而我们要找到第五个节点,
         *   那么在之前的找到的i-1也就是第四个节点
         *  此时q = p->next 返回的就是一个NULL值
         */
        if (q == NULL)
            return ERROR;
        p->next = q->next;
        free(q);
        return TRUE;
    }
}
在逻辑位置之后插入节点

这里注意,插入操作遵循***先右后左***原则,否则会断链,如图:
插入操作

直观代码

/**
 * 在逻辑位置后插入节点
 * @param L  传入链表
 * @param i 逻辑位置
 * @param e 插入数据
 * @return 插入成功返回1,失败返回0
 */
int ListInsert(LinkList *L, int i, int e) {
    int j = 0;
    LinkList *p = L, *s;
    while (j < i && p != NULL) {//查找第i个位置
        j++;
        p = p->next;
    }
    if (p == NULL)//如果为空返回错误值
        return ERROR;
    else {
        s = (LinkList *) malloc(sizeof(LinkList));
        s->data = e;
        s->next = p->next;
        p->next = s;
        return TRUE;
    }
}
按照元素值查找特定节点

这里默认链表中的元素是唯一的,如果想要查找不唯一的数值,就需要大家去拓展了,也不是很难,可以采用将查到的数据逻辑序号放到数组中返回等等等等方法~
直观代码

 /**
  * 按照元素值查找特定节点并返回逻辑序号
  * @param L 传入单链表
  * @param e 传入特定元素
  * @return 没有找到返回0,找到返回逻辑序号i
  */
 int FindElement(LinkList *L, int e){
     int i = 1; //不要忘了初始值!
     LinkList *s = L; //指向开始节点
     while (s != NULL && s->data != e){
         s = s->next;
         i++;
     }
     if (s == NULL )
         return ERROR;
     else
         return i;
 }
输出链表

直观代码

/**
 * 输出单链表
 */
void DispList(LinkList *L) {
    while (L->next != NULL) {
        printf("%d->", L->data);
        L = L->next;
    }
    printf("%d", L->data);
}
最后附上测试用的main函数,为了方便就直接用数组赋值了
#include <stdio.h>
#include "linklist.h"

int main() {

    int a[10];
    for (int j = 0; j < 10; ++j) a[j] = j + 1;
    LinkList *L = (LinkList *) malloc(sizeof(LinkList));

    CreateListByTail(L, a, 10);
    printf("建立完成后的单链表为: ");
    DispList(L);

    ListInsert(L, 5, 555);
    printf("\n在第五个节点后插入555之后的单链表为: ");
    DispList(L);

    ListDelete(L, 3);
    printf("\n删除第三个节点后的单链表为: ");
    DispList(L);

    int i = FindElement(L, 5);
    if (i != 0)
        printf("\n拥有此元素!在第%d个位置上!",i);
    else
        printf("\n没有此元素!!!!");
    return 0;
}

测试结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值