基于嵌入式需要的数据结构---C语言实现单链表和循环链表

为什么要写这篇博客?

嵌入式开发中,在很多的环境下无法使用官方库,可以自己写数据结构,进行使用。

链表特点:

  • 元素前后依赖
  • 不能随机访问元素
  • 易于删除和添加元素(但是需要内存管理机制)

方法:

  • 构造
  • 结点插入
  • 遍历
  • 结点删除
  • 翻转
  • 释放内存

单链表及结点构造

每个结点都有自己的数据内存data,下一个结点的地址用next指针存放。

Node名代表结点,*Linkedlist说明需要一个指针(存储地址)配合各种方法操作链表。

typedef struct Node{
    int data;
    struct Node *next;
}Node, *LinkedList;

 

结点插入(insert(结点指针,位置))

  • 找到链表中要插入的位置
  • 令待插入结点的next指针指向插入位置的当前结点
  • 令待插入位置之前的next指向待插入结点
  • 此时需要逐步遍历查找,所以时间复杂度为O(n)
    LinkedList insert(LinkedList head, Node *node, int index) {
        if (head == NULL) {
            // 向空表的非0位置插入,肯定是错的
            if (index != 0) {
                return head;
            }
            head = node;
            return head;
        }
        if (index == 0) {
            node->next = head;
            head = node;
            return head;
        }
        Node *current_node = head;
        int count = 0;
        // 这里需要根据index对插入位置前的链表进行定位
        // 通过它的next对插入位置处的结点进行访问
        while (current_node->next != NULL && count < index - 1) {
            current_node = current_node->next;
            count++;
        }
        if (count == index - 1) {
            // 先将插入位置结点地址赋给插入结点,否则前一个结点存放的地址就没了
            node->next = current_node->next;
            current_node->next = node;
        }
        return head;
    }

遍历方法(output)

  • 定义一个用于遍历的变量,初始指向头结点
  • 输出遍历遍历所在结点的data,并更新遍历变量为当前结点的下一个结点
  • 重复操作上一步,直到遍历完所有的结点
void output(LinkedList head) {
    if (head == NULL) {
        return;
    }
    Node *current_node = head;
    while (current_node != NULL) {
        printf("%d ", current_node->data);
        current_node = current_node->next;
    }
    printf("\n");
}

 

删除结点(delete_node( index))

  • 从头遍历找到要删除的位置
  • 令删除位置前结点的next指向待删除结点后的结点
  • 删除结点

一开始用一个指针连接head

然后用del代替cur,继续用head索引结点。

最后释放空间。

LinkedList delete_node(LinkedList head, int index) {
    if (head == NULL) {
        return head;
    }
    Node *current_node = head;
	// 这里记得初始化为0
    int count = 0;
    if (index == 0) {
        head = head->next;
        free(current_node);
		//这个也是一个出口
        return head;
    }
	// 定位到指定结点的前一个。
    while (current_node->next != NULL && count < index - 1) {
        current_node = current_node->next;
        count++;
    }
	// 这里是count == index - 1 不是count < index - 1
    if (count == index - 1 && current_node->next != NULL) {
        Node *delete_node = current_node->next;
        current_node->next = delete_node->next;
        free(delete_node);
    }
    return head;
}

 

链表翻转实现(reverse)

  • 定义一个用于遍历的指针,初始指向头结点后的一个结点
  • 让头结点的next指针置空
  • 从当前遍历指针的结点开始遍历,将遍历到的结点next指向头结点,遍历过程借助另一个指针保存下一个遍历到的结点
  • 重复上步骤直至表尾,此时新的链表就是原链表反转后的链表。
// 请在下面实现链表的反转函数 reverse
// 这个函数有疑问。
LinkedList reverse(LinkedList head){
    if(head == NULL){
        return head;
    }
    //遍历过程中下一个结点和当前结点
    Node *next_node, *current_node;
    // current_node指针,指向头结点后结点。
    current_node = head->next;
    head->next = NULL;
    while(current_node != NULL ){
        next_node = current_node->next;
        // cur指向头结点
        current_node->next = head;
        head = current_node;
        current_node = next_node;
    }
    return head;
}

 

释放内存(clear)

  • 定义一个结点del存放传入的地址
  • 传入地址next
  • 释放del即可
void clear(LinkedList head) {
    Node *current_node = head;
    while (current_node != NULL) {
        Node *delete_node = current_node;
        current_node = current_node->next;
        free(delete_node);
    }
}

 

最后用一个简单程序测试函数

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

typedef struct Node{
    int data;
    struct Node *next;

}Node, *LinkedList;

LinkedList insert(LinkedList head, Node *node, int index) {
    if(head == NULL){
        if(index != 0){
            printf("failed\n");
            return head;
        }
        head = node;
        printf("success\n");
        return head;
        
    }
    if(index == 0){
        node->next = head;
        head = node;
        printf("success\n");
        return head;
    }
    Node *current_node = head;
    int count = 0;
    while(current_node->next != NULL && count < index-1){
        current_node = current_node->next;
        count++;
    }
    if(count == index-1){
        node->next = current_node->next;
        current_node->next = node;
        printf("success\n");
        return head;
    }
    printf("failed\n");
    return head;

}

void output(LinkedList head) {
    if(head == NULL){
        return ;
    }
    Node *current_node = head;
    while(current_node != NULL){
        printf("%d", current_node->data);
        if(current_node->next != NULL){
            printf(" ");
        }
        current_node = current_node->next;
    }
    printf("\n");

}

void clear(LinkedList head) {
    Node *current_node = head;
    while(current_node != NULL){
        Node *delete_node = current_node;
        current_node = current_node->next;
        free(delete_node);
        
    }
}

int main() {
    LinkedList linkedlist = NULL;
    int n,p,q;
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		scanf("%d%d", &p, &q);
        Node *node = (Node*)malloc(sizeof(Node));
        node->data = q;
        node->next = NULL;
        linkedlist = insert(linkedlist, node, p);
    }
    output(linkedlist);
 
    clear(linkedlist);

    return 0;
}

双向链表:

 

循环链表(约瑟夫环问题):

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

typedef struct Node{
    int data;
    struct Node *next;
}Node, *LinkedList;

LinkedList insert(LinkedList head, Node *node, int index) {
    if (head == NULL) {
        if (index != 0) {
            return head;
        }
        head = node;
        head->next = head;
        
        return head;
    }
    if (index == 0) {
        node->next = head->next;
        head->next = node;
        //这里的head是尾结点
        return head;
    }
    Node *current_node = head->next;
    int count = 0;
    while (current_node != head && count < index - 1) {
        current_node = current_node->next;
        count++;
    }

    if (count == index - 1) {
        node->next = current_node->next;
        current_node->next = node;
    }
    if(node == head->next){
        head = node;
    }
    return head;
}

// 请在下面实现输出函数 output_josephus
void output_josephus(LinkedList head, int m){
    Node *current_node = head;
    head = NULL;
    while(current_node->next != current_node){
        for(int i = 1; i < m; i++){
            current_node = current_node->next;
        }
        printf("%d ",current_node->next->data);
        Node *delete_node = current_node->next;
        current_node->next = current_node->next->next;
        free(delete_node);
    }
    printf("%d\n",current_node->data);
    free(current_node);
}

int main() {
    LinkedList linkedlist = NULL;
    int n, m;
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; i++){
        Node *node = (Node*)malloc(sizeof(Node));
        node->data = i;
        node->next = NULL;
        linkedlist = insert(linkedlist, node, i-1);
        
    }
	output_josephus(linkedlist, m);
    
    return 0;
}

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值