C语言 单链表基本操作源码

单链表 源码C程序源文件:DataRetrans.c

/**
 * @file    :
 * @date    :20191118
 * @author  :zhoumin
 */ 

#include "DataRetrans.h"
#include "server.h"
#include "rtc.h"
#include <stdbool.h>

#if MALLOC_SWITCH
void *pmalloc(uint32_t size) {  return  calloc(size, sizeof(uint8_t));}

malloc_fn  Retrans_malloc = (malloc_fn)pmalloc;
free_fn  Retrans_free = (free_fn)free;
#else
void* (*Retrans_malloc)(size_t sz) = pvPortMalloc;//malloc;
void (*Retrans_free)(void *ptr) = vPortFree;//free;
#endif

#define QUEUE_SIZE  20

/*初始化单链表*/
void InitList(LNode **HL)
{
	*HL = NULL;  //置单链表为空
}

/*删除单链表中所有节点,使其成为空表*/
void ClearList(LNode **HL)
{
	LNode *cp; //cp(current pointer)指向当前待处理节点
	LNode *np; //np(next pointer)指向cp的后继节点
	cp = *HL; //表头指针赋给cp
	while(cp != NULL){
		np = cp->next;
		Retrans_free(cp);//释放该节点内存
		cp =np; //使下一个节点成为当前节点
	}
	*HL = NULL;
}

/*得到单链表的长度*/
uint16_t LengthList(LNode *HL)
{
	uint16_t i=0;
	while(HL != NULL){
		i++;
		HL = HL->next;
	}
	return i;
}

/*检查单链表是否为空*/
bool EmptyList(LNode *HL)
{
	return HL==NULL;
}

/*得到单链表中第pos个节点中的元素*/ //节点序号从表头的序号1开始
ElemType GetList(LNode *HL, uint16_t pos) //pos>=1
{
	if(pos < 1){
		LOG_L("pos is Wrongful!");
		return NULL;
	}
	uint16_t i= 0;
	while(HL != NULL){
		i++;
		if(i == pos)
			break;
		HL = HL->next;
	}
	if(HL != NULL){  //不为空,说明已找到该节点
		return HL->data;
	}
	else{
		LOG_L("pos is out range!");//没找到
		return NULL;
	}
}

/*遍历一个链表*/
void TraverseList(LNode *HL)
{
	while(HL != NULL){
		//LOG_L(fmt, args...);
		HL = HL->next;
	}
}

/*从链表中查找出给定值的第一个元素,并由item带回该值*/
bool FindList(LNode *HL, ElemType *item)
{
	while(HL != NULL){
		if(*item == HL->data){ //根据具体比对项,修改此处代码
			*item = HL->data;  //根据具体比对项,修改此处代码
			return true;
		}
		else{
			HL = HL->next;
		}
	}
	return false;
}

/*更新链表中等于给定值的第一个元素*/
bool UpdateList(LNode *HL, const ElemType *item)
{
	while(HL != NULL){
		if(HL->data == *item)
			break;
		else
			HL = HL->next;
	}
	if(HL == NULL)	//没有找到给定值的元素,无法更新
		return false;
	else{
		HL->data = *item;
		return true;
	}
}

/*向单链表中按给定条件插入一个元素*/ //表头节点的序号指定为1,pos==1,表示插入到表头
bool InsertList(LNode **HL, ElemType item, int pos) //pos必须大于等于-1;pos:0 按值寻找插入位置  pos:-1插入到表尾  pos:>0 插入到pos指定序号位置
{
	if(pos < -1){
		LOG_L("pos is Wrongful!");
		return false;
	}
	//为item元素建立新节点
	LNode *newptr;
	newptr = (LNode *)Retrans_malloc(sizeof(LNode));
	newptr->data = item;
	//寻找新节点的插入位置
	LNode *cp = *HL;  //cp指向当前节点,即待查节点,初始为指向表头
	LNode *ap = NULL; //ahead pointer 指向cp的前驱节点,初始化空
	if(pos == 0){	//pos:0 按值寻找插入位置
		while(cp != NULL){
			if(item < cp->data) //根据具体比对内容,修改此处代码
				break;  //找到新元素的插入位置,退出循环
			else{
				ap = cp;
				cp = cp->next;
			}
		}
	}
	else if(pos == -1){   //pos:-1插入到表尾
		while(cp != NULL){
			ap =cp;
			cp = cp->next;
		}
	}
	else{    //pos:>0 插入到pos指定序号位置
		int i = 0;
		while(cp != NULL){
			i++;
			if(i == pos){ //pos==1,表示插入到表头
				break;
			}
			else{
				ap = cp;
				cp = cp->next;
			}
		}
		if(cp == NULL && i <pos){  //ypl-教材应该有误,教材源码: (cp == NULL && i+1 <pos)
			LOG_L("pos is not exist!");
			return false;
		}		
	}

	//完成新节点的插入操作
	if(ap == NULL){  //ap为空,表示,将要插入的节点位置就是表头--表头的前驱节点就是空
		newptr->next = *HL;
		*HL = newptr;
	}
	else{  //把新节点插入到非表头位置,即插入到ap和cp之间
		newptr->next = cp;  //cp如果为空,则表示插入到表尾
		ap->next = newptr;
	}

	return true;
}


/*从单链表中删除符合给定条件的第一个元素*/
bool DeleteList(LNode **HL, ElemType *item, int pos) //pos必须大于等于-1;pos:0 按值寻找待删节点  pos:-1待删节点是表尾  pos:>0 插入到pos指定序号位置
{
	//单链表为空,无法删除,返回假
	if(*HL == NULL){
		LOG_L("LIST is empty!");
		return false;
	}
	//pos值小于-1,返回假
	if(pos < -1){
		LOG_L("pos's value is invalid!");
		return false;
	}
	//寻找需要被删除的元素的节点
	LNode *cp = *HL;  //cp指向当前节点,即待查节点,初始为指向表头
	LNode *ap = NULL; //ahead pointer 指向cp的前驱节点,初始化空
	if(pos == 0){    //按值查找被删除节点
		while(cp != NULL){
			if(*item == cp->data)
				break;
			else{
				ap = cp;
				cp = cp->next;
			}
		}
		if(cp == NULL){
			LOG_L("pos's value can't find!");
			return false;
		}
	}
	else if(pos == -1){    //查找表尾节点
		while(cp->next != NULL){
			ap = cp;
			cp = cp->next;
		}
	}
	else{    //查找给定序号的节点
		int i = 0;
		while(cp != NULL){
			i++;
			if(i == pos){
				break;
			}
			else{
				ap = cp;
				cp = cp->next;
			}
		}
		if(cp == NULL){
			LOG_L("pos is over lenth!");//指定序号越界超过链表实际长度
			return false;
		}
	}

	//删除cp指向的节点
	if(ap == NULL){ //删除表头节点
		#if 1
		LNode *temp = *HL;  //ypl-语法可能出错的备用方案  	  
		*HL = temp->next;
		#else
		*HL = (*HL)->next;//ypl-语法不标准,但仍旧能够编译过  	  
		#endif
	}
	else{ //删除非表头节点,也可能是表尾节点
		ap->next = cp->next;
	}
	//回收被删除节点的存储空间
	Retrans_free(cp);//ypl-实际上,要回收的数据还不止节点占用的空间,还有

	return true;
}



/*对单链表进行数据排序
 *假定待排序的单链表由表头指针HL所指向,对节点值按照从小到大进行排序链接时,首先建立一个空的单链表,
 *然后把HL中的每个节点取出来并按值依次插入到新建立的单链表中,最后由HL带回新建链表的表头指针
 */
 void SortList(LNode **HL)
{
	//建立一个反映排序结果的新单链表,并初始化为空
	LNode *SL;
	InitList(&SL);
	//从待排序的HL单链表中依次取出每个节点,并按值由小到大插入到新单链表中
	LNode *r=*HL;  //r指向待取出排序的一个节点,初始化为HL表头节点
	LNode *t;  //t指向r的后继节点
	LNode *cp; //指向已排序的新链表,初始化为表头SL
	LNode *ap; //ap指向cp的前驱节点,初始化为空
	while(r != NULL)
	{
		//为新插入的r节点在SL中顺序查找出插入位置
		t = r->next; //t指向原链表r节点的后继节点
		cp = SL;     //指向已排序的新链表,初始化为表头SL
		ap = NULL;   //ap指向cp的前驱节点,初始化为空
		while(cp != NULL)
		{
			if(r->data < cp->data)  
				break;  //找到被插入点,退出循环
			else{
				ap = cp;        //ap和cp均后移,实现有序链表中的每个节点依次顺序和原链表中r节点比较
				cp = cp->next;
			}
		}

		//实现插入操作
		if(ap == NULL){  //把r节点插入到表头
			r->next = SL;
			SL = r;
		}
		else{            //把r节点插入到ap和cp之间
			r->next = cp;
			ap->next = r;
		}

		//使r指向原链表的下一个节点
		r = t;
	}

	//返回链表排序结果
	*HL = SL;
}









QueueHandle_t xQueue;     
//osSemaphoreId xComRxSem;
struct Repeat_Qmsg *reMsgHead  = NULL;
LNode *reMSGHead;



/**
 * 数据单元内存释放
 */ 
void FreeQMsg(QMsg *pmsg)
{
    if(pmsg != NULL)
    {
        if(pmsg->message.data != NULL) 
        {
            Retrans_free(pmsg->message.data);
            pmsg->message.data = NULL;
        }
        Retrans_free(pmsg);
        pmsg = NULL;
    }
}

int PutToRepeatQmsg(QMsg *data)
{
    struct Repeat_Qmsg *p = (struct Repeat_Qmsg *)Retrans_malloc(sizeof(struct Repeat_Qmsg));
    if(p == NULL)
    {   
        LOG_E("malloc error.\r\n");
        return CL_FAIL;
    }
    p->data = data;
    
    if(reMsgHead == NULL)
    {
        p->next = NULL;
        reMsgHead = p;
    }
    else
    {
        p->next = reMsgHead;
        reMsgHead = p;
    }
    
    return CL_OK;
}

void RepeatQmsgLoop(void)
{
    struct Repeat_Qmsg *p = reMsgHead;
    struct Repeat_Qmsg *last = NULL ,*temp;
    QMsg *data = NULL;
	
    while (p != NULL)
    {
        if(GetTimeStamp() >= p->data->timestamp+3000)
        {
            data = p->data;
            //将节点数据添加到发送队列
            if(xQueueSendToBack(xQueue,(void*)&data,0) != pdTRUE)
            {
                LOG_E("send to queue error.\r\n");
                FreeQMsg(data);//添加队列失败,释放数据单元内存
            }
            /* 删除节点p  */
            temp = p; //记录节点
            if(p == reMsgHead)//p指向头节点
            {
                reMsgHead = p->next;
            }
            else
            {
                last->next = p->next;
            }
			last = p;
			p = p->next;
            Retrans_free(temp);//释放该节点内存
            temp = NULL;
        }
        else
        {
			last = p;
            p = p->next;
        }
    }
}



int DataRetrans_SendMsg(Message_Unit message,timeout_callback callback)
{
    BaseType_t ret ;
    if(message.data == NULL)
        return CL_FAIL;
    
    QMsg *pmsg = (QMsg *)Retrans_malloc(sizeof(QMsg));
    if(pmsg == NULL)
    {
        LOG_E("malloc queue msg failed.\r\n");
        return CL_FAIL;
    }
    pmsg->message = message;
    pmsg->flag = 1;
    pmsg->callback = callback;
    pmsg->timers = 1;

	ret = xQueueSendToBack(xQueue,&pmsg,0);
	//ret = xQueueSendToFront(xQueue,&pmsg,0);

    if(ret != pdTRUE)
    {
        LOG_E("send msg to queue error.\r\n");
        Retrans_free(pmsg);
        return CL_FAIL;
    }
    return CL_OK;
}


void BswSrv_485SendTask(void *argc)
{
    uint32_t values = 0;
    QMsg *pmsg = NULL;
    BaseType_t ret;

    //UNUSED(argc);
	
    while (1)
    {
		vTaskDelay(300);
		Feed_WDT();
		ret = xQueueReceive(xQueue,(void*)&pmsg, 5/*portMAX_DELAY*/);

        if(ret == pdTRUE && pmsg != NULL)
        {
            //发送消息
			//LOG_I("-->msg:%s \r\n",pmsg->message.data);
			//PrintfData(">>msg:",pmsg->message.data,pmsg->message.len);
			//BswDrv_UsartSend(CHG_UART_INDEX, pmsg->message.data,pmsg->message.len);


                pmsg->timers++;
                pmsg->timestamp = GetTimeStamp();

            
            //等待消息ACK 最多等待200ms
            values = ulTaskNotifyTake(pdTRUE,200);
			

            if(values == 1)//收到ack
            {
                FreeQMsg(pmsg);
            }
            else if(pmsg->flag == 1)//超时
            {
                if(pmsg->timers >= 3)
                {
                    FreeQMsg(pmsg);
                    if(pmsg->callback) pmsg->callback();
                    //LOG_I("send data timeout.\r\n");
                }
                else
                {
                    //添加到重发队列
                    PutToRepeatQmsg(pmsg);
					LOG_E("PutToRepeatQmsg. \r\n");
                }
            }
            else
            {
                FreeQMsg(pmsg);
                //LOG_I("wait ack timeout.\r\n");
            }
        }

        //轮询重发队列
        RepeatQmsgLoop();
    }
}



/**
 * 485总线任务初始化 
 */ 
void BswSrv_485TaskInit(void)
{
    xQueue = xQueueCreate(QUEUE_SIZE, sizeof(QMsg *));
    //xComRxSem = osSemaphoreCreate(NULL,10);
    reMsgHead = NULL;
}

 

单链表 源码C程序头文件:DataRetrans.h

#ifndef __DATA_RESTRANS_H_
#define __DATA_RESTRANS_H_

#include "includes.h"


//typedef enum {FALSE   = 0, TRUE   = !FALSE  }   Bool;


typedef void (*timeout_callback) (void);


/**
 * 消息单元
 */ /*重发数据区*/
typedef struct
{
    uint16_t len;	//数据长度
    void *   data;	//数据缓存区
    uint16_t msgId;	//流水号
	uint8_t  cmd;	//指令
}Message_Unit;

/**
 * 队列数据单元
 */ 
typedef struct
{
	/*重发数据区*/
    Message_Unit message;
	/*重发控制器*/
    uint8_t  flag;                  //未收到应答的重发标志 1:正在重发 0:结束重发
    uint8_t  timers;                //当前发送次数
    uint32_t timestamp;             //上次发送时间戳
    timeout_callback callback;		//超时回调函数	
}QMsg;

typedef QMsg* ElemType;

struct _LNode{
	ElemType data;
	struct _LNode *next;
};
typedef struct _LNode LNode;





/**
 * 重传消息链表
 */ 
struct Repeat_Qmsg
{
    QMsg *data;
    struct Repeat_Qmsg *next;
};

#define MALLOC_SWITCH  1 //0

#if MALLOC_SWITCH
typedef void *(*malloc_fn)(size_t sz);
typedef void (*free_fn)(void *ptr);

extern malloc_fn  Retrans_malloc;//malloc;
extern free_fn  Retrans_free;//free;
#else
extern void *(*Retrans_malloc)(size_t sz);//malloc;
extern void (*Retrans_free)(void *ptr);//free;
#endif



int DataRetrans_SendMsg(Message_Unit message,timeout_callback callback);

void BswSrv_485TaskInit(void);

#endif

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值