zoukankan      html  css  js  c++  java
  • C语言实现通用链表初步(一)

    注意:本文讨论的是无头单向非循环链表。

    假设不采用Linux内核链表的思路,怎样用C语言实现通用链表呢?

    一种常用的做法是:

    typedef int element_t;

    struct node_info

    {

    element_t data;

    struct node_info *next;

    };


    其实这样的链表算不上通用,因为无法同时使用不同的数据类型。参考网友的思路,以上可以改为下面的定义:

    //无头非循环单向链表
    struct node_info {
    	void *data;
    	struct node_info *next;
    };

    先看看头文件:

    #pragma once
    
    
    //无头非循环单向链表
    struct node_info {
    	void *data;
    	struct node_info *next;
    };
    
    
    
    struct student
    {
    	char name[20];
    	unsigned char age;
    
    };//for test
    
    struct  slist_info {
    	struct node_info *first; //指向第一个节点
    	
    	void (*insert_head)(void *one_data, 
    			struct slist_info *info);//头插
    	
    	int (*del)(struct node_info *node, 
    			struct slist_info *info);//删除节点
    
    	struct node_info* (*find)(struct slist_info *info,
    					int(*compare)(void *dest,void *key),void *key);
    	//这里的compare是回调函数,由用户提供
    
    	void (*for_each)(const struct slist_info *info,
    			void (*todo)(void *one_data));//遍历,todo是回调函数
    
    	void (*for_each_safe)(const struct slist_info *info,
    			void (*todo)(void *one_data));//安全遍历(觉得在这里这个方法意义不大)
    
    	void (*invert)(struct slist_info *info);//反转链表
    
    	int (*is_dead_loop)(struct slist_info *info);//判断是否有死环,是返回1,不是返回0
    };
    
    #define   slist_is_empty(info)  ((info)->first == NULL) //链表是否为空
    
    //构造和析构
    void  slist_init(struct  slist_info *info);
    void  slist_destroy(struct slist_info *info);
    
    
    
    


    与这个链表相关的操作如下。

    1.插入元素(头插法)

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
    #include "slist.h"
    
    /*无头非循环单链表*/
    static void slist_insert_head(void *one_data, 
                            struct slist_info *info)
    {//头插法
    	assert(one_data != NULL && info != NULL);
    	
    	
    	struct node_info *node = 
    		(struct node_info *)malloc(sizeof(struct node_info));//分配内存
    	assert(node!=NULL);
    	
    	node->data = one_data;//注意,这里只是简单地把指针指向用户的数据,并没有把用户数据复制过来
    	
    	if (slist_is_empty(info)) {//1.空链表
    		info->first = node;
    		node->next = NULL;
    	}else { //2. 非空
    		node->next = info->first;
    		info->first = node;
    	}
    }

    2.遍历

    static void slist_for_each(const struct slist_info *info,
           							void (*todo)(void *one_data))
    {
    	assert(info != NULL && todo != NULL);
    	struct node_info *cur = NULL;
    
    	for (cur = info->first; cur != NULL; cur = cur->next) {
    		todo(cur->data);
    	}
    }
    
    static void slist_for_each_safe(const struct slist_info *info,
           							void (*todo)(void *one_data))
    {
    	assert(info != NULL && todo != NULL);
    	struct node_info *cur = NULL;
    	struct node_info *Next = NULL;
    	for (cur = info->first; cur != NULL; cur = Next) {
    		Next = cur->next;//Next保存了下一个节点,如果这个节点被删除了,那么下一个节点还可以找到
    		todo(cur->data);
    	}
    }

    3.反转(面试的时候,有可能会问到,直接背过好了!)

    static void  slist_invert(struct slist_info *info)
    {
    	assert(info != NULL);
    
    	struct node_info *Cur = NULL;
    	struct node_info *Prev = NULL;
    	struct node_info *Next = NULL;
    	//1.移动Next 2.反向 3.移动Prev 4.移动Cur
    	for (Cur = info->first; Cur  != NULL; Cur = Next) {
    		Next = Cur->next;
    		Cur->next = Prev;
    		Prev = Cur;
    	}
    	//修改头指针,指向首节点
    	info->first = Prev;	
    }

    4.查找


    struct node_info *slist_find(struct slist_info *info,int(*compare)(void *dest,void *key),void *key)
    {
    	assert(info != NULL && compare != NULL);
    	struct node_info *cur = NULL;
    
    	for (cur = info->first; cur != NULL; cur = cur->next) {
    		if(compare(cur->data,key)==1)//回调函数,把链表中的每一个数据和用户传入的关键字做比较,符合条件返回1
    			return cur;//返回节点的地址给用户
    	}
    	return NULL;//没有找到返回空指针
    }

    注意,这里的第三个参数(关键字)也是用户传进来的。


    5.构造和析构

    void slist_init(struct slist_info *info)
    {
    	//空链表, 第一个节点为NULL
    	info->first = NULL;
    
    	info->insert_head = slist_insert_head;
    	info->del = slist_del;
    	info->find = slist_find;
    	info->invert = slist_invert;
    	info->is_dead_loop = slist_is_dead_loop;
    	info->for_each = slist_for_each;
    	info->for_each_safe = slist_for_each_safe;
    }
    
    void slist_destroy(struct slist_info *info)
    {
    	if(!slist_is_empty(info))
    	{
    		struct node_info *cur = NULL;
    		struct node_info *Next = NULL;
    		for (cur = info->first; cur != NULL; cur = Next) 
    		{
    			Next = cur->next;//Next保存了下一个节点,如果这个节点被删除了,那么下一个节点还可以找到
    			free(cur);//释放每个节点占用的内存
    		}
    	}
    	
    }

    细心的读者会发现,好像有的函数没有实现啊。下一篇博文我们再讨论!


  • 相关阅读:
    元组,字典
    for循环补充,变量和不可变量,数字类型,字符串类型,列表类型
    流程控制之while循环,for循环
    运算符,流程控制之if判断
    变量,常量,基本数据类型、运算符
    蓝桥杯--算法提高 排列数 (简单dfs)
    蓝桥杯-- 历届试题 核桃的数量 (gcd)
    hdoj--1272--小希的迷宫(并查集)
    zzulioj--1769--去师院的旅程:能怎么走(三)(0.0)
    zzulioj--1638--Happy Thanksgiving Day
  • 原文地址:https://www.cnblogs.com/longintchar/p/5224445.html
Copyright © 2011-2022 走看看