[数据结构]单链表C语言的简单实现

Github:(https://github.com/FlameCharmander/DataStructure)
本来是在和顺序表里放一起写。但是考虑简洁的话,就这样写了。
直接上链表的代码了。

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

typedef char ElemType;
typedef int BOOL;
#define TRUE 1
#define FALSE 0

typedef struct LinkNode{
    ElemType data;
    struct LinkNode* next;
}LinkList, Node;

void InitList(LinkList *list);   //初始化链表
BOOL Insert(LinkList *list, ElemType e, int pos);   //将元素插入
BOOL Delete(LinkList *list, ElemType e);    //将指定元素删除
BOOL IsEmtpy(LinkList *list);   //判断链表是否为空

int main()
{
    LinkList list;
    InitList(&list);
    printf("%d\n", IsEmtpy(&list));
    Insert(&list, 'a', 1);
    Insert(&list, 'b', 2);
    Insert(&list, 'c', 1);
    Delete(&list, 'a');
    Node *p = list.next;
    while (p != NULL) {
        printf("%c ", p->data);
        p = p->next;
    }
    printf("\n%d\n", IsEmtpy(&list));
    Delete(&list, 'b');
    Delete(&list, 'c');
    printf("%d\n", IsEmtpy(&list));
    return 0;
}

void InitList(LinkList *list){
    list->next = NULL; //设置一个头结点
}

BOOL Insert(LinkList *list, ElemType e, int pos){
    int i;
    Node* pre = list;
    for (i = 1; i < pos; ++i){
        pre = pre->next;
    }
    Node *node = (Node *)malloc(sizeof(Node));
    node->data = e;
    node->next = pre->next;
    pre->next = node;
    return TRUE;
}

BOOL Delete(LinkList *list, ElemType e){
    Node* pre = list;
    while (pre->next != NULL) {
        if (pre->next->data == e){
            Node* q = pre->next;    //临时存储
            pre->next = pre->next->next;
            free(q);
            return TRUE;
        } else {
            pre = pre->next;
        }
    }
    return FALSE;
}

BOOL IsEmtpy(LinkList *list){
    if (list->next == NULL) {
        return TRUE;
    } else {
        return FALSE;
    }
}

老规矩,要对代码做一个解释了,可以再开窗口对照着看。
Line 1~2 是导入头文件
Line 4 Typedef是给用来为复杂的声明定义简单的别名,所以这里我这里设置ElemType char,如果到时链表的元素类型不是char,比如只要int,只需typedef int ElemType。
Line 5~7 由于C语言没有布尔类型,所以这里用了int代替,1代表True,0代表False
Line 9~12 这是链表的数据结构,如果不太熟的话,去看看理论部分吧。
Line 14~17 函数的声明,如果函数写在main函数下面,需要在这里做个定义
Line 19~38 这里是main函数,就是将所写的操作给测试一下,看有没有出错
Line 40~42 这里默认链表是有头结点的,这样插入和删除等会方便很多,如果你不知道头结点是什么,我简单说下,头结点就是一个没有值的结点,下面会讲为什么需要投结点。
Line 44~55 这就是我们的插入操作了。1<=pos<=n。
Line 46 pre代表是前一个结点的意思。我画了张图,是链表插入了元素a,b之后的图。
插入a和b之后的链表
第一个没有值的结点就是头结点了,现在我们要插入c到1的位置,也就是a的前面,那么我们需要a之前的结点(现在这个结点是头结点)才能把c插入到a的前面对吧。
那你试想下,如果没有头结点的话,那是不是还要判断插入结点是第一个结点还是第一个结点之后。(你们想象下没有头结点的插入就知道了)
Line 47~49 这个是寻找要插入的位置的前一个结点
Line 50~51 申请一个新的结点,并把要插入的元素(现在是c)赋值到数据域,我们即将要把它插入到我们想要的位置。
Line 52~54 看下下面这个图
插入c

node->next = pre->next;将c的指针域指向到a
pre->next = node;将pre结点(现在是头结点)的指针域指向c
然后返回真,这就完成了一次插入操作,请注意,我们要插入一个结点,需要的是前一个结点。
Line 57~70 删除操作
我们把刚才的插入完C的表重新调整一下。
插入C之后的链表
Line 59 是遍历全部结点
删除a
Line 60 是找到要删除的结点的前一个结点
Line 61 用指针q指向结点a,看图
Line 62 比如现在找到了c(a的前一个结点),那我们要把a删除,把c的指针域指向b结点即可
Line 63 这时结点a就没有了任何存在的意义了,我们需要手动释放它,这里的Line 61~63的顺序是不能换的,耐人寻味。为什么不能先释放呢,因为我们如果先释放了,那我们c结点就找不到a结点的后一个结点b了
Line 72~78 由于有头结点,所以判断的条件next是否为空。

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
循环单链表链表的一种特殊形式,它的特点是链表中的最后一个节点的指针指向第一个节点,形成一个闭合的环。在C语言中,操作循环单链表通常涉及创建、插入、删除和遍历等基本操作。 以下是一些基本操作的C语言实现概览: 1. **创建循环链表**: - 定义节点结构体,包含数据域和指向下一个节点的指针(如果是在头结点的最后一个节点,指针会指向自身)。 - 创建链表时,可以初始化一个头节点,然后递归地添加新节点到链尾。 ```c struct Node { int data; struct Node* next; }; // 创建循环链表 void createCircularList(struct Node** head, int size, ...) { ... } ``` 2. **插入节点**: - 可以在链表的头部、尾部或指定位置插入节点。 - 在头部插入,更新头节点的next;在尾部插入,找到当前尾节点,然后更新其next指向新节点,并将新节点next指向头节点。 ```c void insertNode(struct Node** head, int data, insertionPosition) { struct Node* newNode = (struct Node*)malloc(sizeof(struct Node)); newNode->data = data; newNode->next = (insertionPosition == 1) ? head : (*(head)->next); // 如果在尾部插入,更新尾节点和头节点的next指针 if (insertionPosition == 0) { (*head)->next = newNode; } } ``` 3. **删除节点**: - 删除某个节点时,需要找到前一个节点,然后更新其next指针跳过要删除的节点。 - 在循环链表中删除特定位置的节点需要特别处理头节点的情况。 ```c void deleteNode(struct Node** head, int position) { if (position == 1) { // 删除头节点 struct Node* temp = head->next; *head = temp; free(head); } else { struct Node* current = *head, *previous = NULL; for (int i = 1; i < position && current != NULL; ++i) { previous = current; current = current->next; } if (current == NULL) return; // 未找到节点 previous->next = current->next; } } ``` 4. **遍历循环链表**: - 使用while循环,每次迭代都更新当前节点指向下一个节点,直到遇到第一个节点。 ```c void printList(struct Node* head) { struct Node* temp = head; do { printf("%d ", temp->data); temp = temp->next; } while (temp != head); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值