单向链表

  链表是Linux内核中最简单、最普通的数据结构。链表是一种存放和操作可变数量元素的数据结构。链表和静态数组的不同之处在于,它所包含的元素都是动态创建并插入链表的,在编译时不必知道具体需要创建多少个元素。另外也因为链表中的每个元素的创建时间各不相同,所以它们在内存中无须占用连续内存区。正是因为元素不连续地存放,所以各元素需要通过某种方式被连接在一起。于是每个元素都包含一个指向下一个元素的指针,当有元素加入链表或从链表中删除元素时,简单调整指向下一个节点的指针就可以了。
  这次使用的Makefile需要将各个文件连接,而且文件都不在一个目录下,现在我们来看一下这个目录树:

list/
├── header
│   └── list.h
├── source
│   └── list.c
└── user
    └── Makefile

  目的是在user文件下生成输出文件。
Makefile

HEADER_PATH = ../header/
SOURCE      = ../source/list.c
HEADER      = ../header/list.h
TARGET      = list

TARGET:$(SOURCE) $(HEADER)
    gcc -o $(TARGET) $(SOURCE) -I$(HEADER_PATH) -Wall

.PHONY:clean
clean:
    rm -f $(TARGET)

list.h

#ifndef __LIST_H
#define __LIST_H

#include <stdio.h>
#include <malloc.h>
/**定义一个链表结构体**/
struct Node{
    int data;
    struct Node *next;
};

/**创建链表**/
struct Node *creat(int n)
{
    int i,data; 
    struct Node *head,*p1,*p2;          //head为链表的头,p1指向每次新分配的内存空间,p2总是用来指向尾节点且通过p2链入新分配的节点
    head = NULL;                        //初始化链表头指针

    for(i = 0; i < n; i++){
        printf("请输入链表第%d个节点的值:",i+1);
        scanf("%d",&data);
        p1 = (struct Node*)malloc(sizeof(struct Node));     //分配地址
        p1->data = data;
        if(head == NULL){               //如果是创建的是第一个链表节点
            head = p1;                  //作为头
            p2 = p1;                    //p2准备链入下一个节点
        } else {
            p2->next = p1;              //链入下一个节点
            p2 = p1;                    //准备链入下一个节点
        }
        p2->next = NULL;                //结束
    }
    return head;
}

struct Node *reverse(struct Node *head)
{
    struct Node *p,*r;
    if(head->next && head->next->next){ //链表长度在三个或以上才可以逆置
        p = head;                       
        r = p->next;
        p->next = NULL;
        while(r){
            p = r;
            r = r->next;
            p->next = head;
            head = p;
        }
        return head;
    }
    return head;
}

#endif

list.c

/************************************************
    **创建单链表
************************************************/

#include "list.h"

int main(void)
{

    int n;
    struct Node *head,*current;
    printf("输入你想创建的链表节点数\n");
    scanf("%d",&n);
    head = creat(n);
    n = 0;
    printf("----------显示创建的链表-------\n");
    current = head;
    while(current){
        printf("第%d个链表节点数据:%d\n",++n,current->data);
        current = current->next;
    };
    printf("----------逆置后的链表---------\n");
    current = reverse(head);
    n = 0;
    while(current){
        printf("第%d个链表节点数据:%d\n",++n,current->data);
        current = current->next;
    };
    n = 0;
    return 0;
}

2017-11-24-LR

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、linux内核链表 1、普通链表的数据区域的局限性 之前定义数据区域时直接int data,我们认为我们的链表中需要存储的是一个int类型的数。但是实际上现实编程中链接中的节点不可能这么简单,而是多种多样的。 一般实际项目中的链表,节点中存储的数据其实是一个结构体,这个结构体中包含若干的成员,这些成员加起来构成了我们的节点数据区域。 2、一般性解决思路:即把数据区封装为一个结构体 (1)因为链表实际解决的问题是多种多样的,所以内部数据区域的结构体构成也是多种多样的。 这样也导致了不同程序当中的链表总体构成是多种多样的。 我们无法通过一套泛性的、普遍适用的操作函数来访问所有的链表,意味着我们设计一个链表就得写一套链表的操作函数(节点创建、插入、删除、遍历……)。 (2)实际上深层次分析会发现 不同的链表虽然这些方法不能通用需要单独写,但是实际上内部的思路和方法是相同的,只是函数的局部地区有不同。 实际上链表操作是相同的,而涉及到数据区域的操作就有不同 (3)问题 能不能有一种办法把所有链表中操作方法里共同的部分提取出来用一套标准方法实现,然后把不同的部分留着让具体链表的实现者自己去处理。 3、内核链表的设计思路 (1)内核链表中实现一个纯链表的封装,以及纯链表的各种操作函数 纯链表就是没有数据区域,只有前后向指针; 各种操作函数是节点创建、插入、删除、遍历。 这个纯链表本身自己没有任何用处,它的用法是给我们具体链表作为核心来调用。 4、list.h文件简介 (1)内核中核心纯链表的实现在include/linux/list.h文件中 (2)list.h中就是一个纯链表的完整封装,包含节点定义和各种链表操作方法。 二、内核链表的基本算法和使用简介 1、内核链表的节点创建、删除、遍历等 2、内核链表的使用实践 (1)问题:内核链表只有纯链表,没有数据区域,怎么使用? 使用方法是将内核链表作为将来整个数据结构的结构体的一个成员内嵌进去。类似于公司收购,实现被收购公司的功能。 这里面要借助container_of宏。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值