Linux嵌入式学习——数据结构——线性表的链式结构

线性表的链式存储
    解决顺序存储的缺点,插入和删除,动态存储问题。
特点:
    线性表链式存储结构的特点是一组任意的存储单位存储线性表的数据元素,存储单元可以是连续的,也可以不连续。可以被存储在任意内存未被占用的位置上。
    
    所以前面的顺序表只需要存储数据元素信息就可以了。在链式结构中还需要一个元素存储下一个元素的地址。
    
    为了表示每个数据元素,ai与其直接后继数据元素ai+1之间的逻辑关系,对ai来说,除了存储其本身的信息外,还需要存一个指示器直接后续的信息。把存储元素信息的域叫数据域,把存储直接后继位置的域叫指针域。这两部分信息组成数据元素ai的存储映像,叫结点(Node);
    
    
    
    单链表中,c语言的描述
 

typedef struct person {
    char name[32];
    char sex;
    int age;
    int score;
}DATATYPE;

typedef struct node {
    DATATYPE data;
    struct node *next,*prev;         ->这里必须要加指针
}LinkNode;

typedef struct list {
    LinkNode *head;
    int tlen;  链表元素总个数 这里可以不要
    int clen; 当前节点个数

     (mutex 这部分有可能是并发的,有可能需要加上互斥锁)
}LinkList;

       以下是一个链表(LinkList)的操作集,这些操作包括创建链表、在链表头部或尾部插入节点、显示链表内容、查找链表中的节点、删除链表中的节点、修改链表节点的数据和销毁链表。这里,我假设LinkList是一个指向链表头节点的指针,而LinkNode是链表节点的结构体。DATATYPE是一个占位符,表示链表节点存储的数据类型,可能是整型、字符型或其他自定义类型。以下是对每个函数的基本实现思路(不包含完整代码):

1. LinkList *CreateLinkList(int len);

这个函数用于创建一个具有指定长度(len)的空链表。如果len是0,则创建一个空链表(只有一个头节点,头节点的下一个指针指向NULL)。如果len大于0,则可能需要根据实际需求创建len个空节点(或带初始值的节点)的链表。但通常,len参数在这里可能不太适用,因为链表长度是动态变化的,更常见的做法是不带参数地创建一个空链表。

2. int InsertHeadLinkList(LinkList *list, DATATYPE data);

在链表的头部插入一个新节点,该节点包含指定的数据data。函数返回成功或失败的状态码。

若需要在当前表头结点插入一个新结点 , 只需要修改一个next指针(新结点的next指针) , 可以分两步完成

  1. 定义节点结构体:首先,需要定义一个节点结构体,该结构体包含数据域和指针域。数据域用于存储节点的数据,指针域用于存储指向下一个节点的指针。

  2. 初始化链表:创建一个头节点,该节点不存储有效数据,仅作为链表的入口点。头节点的指针域初始化为NULL,表示链表为空。

  3. 插入新节点:对于每次插入操作,首先创建一个新节点,并为其数据域赋值。然后,将新节点的指针域指向头节点的下一个节点(即原链表的第一个节点),最后修改头节点的指针域,使其指向新节点。

* 修改新结点的next指针 , 使其指向当前的表头结点

* 更改表头指针的值 , 使其指向新节点(之前的表头指针指向的是15 , 修改后指向为新数据的)

3. int ShowLinkList(LinkList *list);

遍历链表,并打印出每个节点的数据。这个函数没有返回值(或返回一个状态码表示成功或失败,但通常打印操作不需要)。

4. LinkNode *FindLinkList(LinkList *list, char *name);

在链表中查找具有指定名称(name)的节点。由于函数返回类型为LinkNode *,它返回找到的节点的指针,如果未找到则返回NULL。这里假设每个节点都有一个name属性,这与DATATYPE数据类型的定义可能不一致,需要根据实际数据结构调整。

其中可以定义一个函数指针,来找结构体中不同得东西来达到解耦合的情况

5. int DeleteLinkList(LinkList *list, char *name);

从链表中删除具有指定名称(name)的节点。函数返回成功或失败的状态码。

删除中间节点

(1)使tmp指向想要删除的节点

(2)将tmp的下一个的prev与tmp本身的上一个相等 

(3)使tmp的上一个的nxt与tmp本身的next相等 得到指向tmp节点的下一个节点。 

(4)但如果是最后的节点 ,只要使前一个的下一个置为空就行。但无法找到本身的下一个,会发生错误,所以需要加上一个判断。

6. int ReviseLinkList(LinkList *list, char *name, DATATYPE data);

使链表反转

定义三个指针,分别表示正在操作的节点(prve),以及该节点的上一个(tmp),该节点的下一个(next)

(1)将tmp=head;prve=NULL;next=tmp->next;

  (2)反转tmp本身的prve和next指针

tmp-》next=prve;  tmp->prev=next;

(3)将最初定义的大指针一个一个往后移,直到最后tmp为空,

prve = tmp;

tmp=next;

next =next->next;

(4)将head与最初定义的prev相等。

7. int DestroyLinkList(LinkList *list);

销毁链表,释放链表占用的所有内存空间。函数返回成功或失败的状态码。

使tmp指向第一个节点,一个一个往后释放,最后释放head;

8. int InsertTailLinkList(LinkList *list, DATATYPE data);

在链表的尾部插入一个新节点,该节点包含指定的数据data。函数返回成功或失败的状态码。

9. int ModifyDouLinkList(LinkList *list, DATATYPE data);

改变某个节点的数据。函数返回成功或失败的状态码

9. int InserPosDouLinList(LinkList *list, DATATYPE data);

(1)如果head里没有节点   clen=0(链表是空)或者想要插入的pos=0;直接调用头插

(2)head后有节点

将tmp移到想要插入位置的前一个节点;

while(pos-1)

{

       tmp=tmp->next;

使newnode的prev指向tmp,newnode 的next指向原来tmp指向的位置;

newnode->prve=tmp;

newnode->next=tmp->next;

 如果tmp后面没东西,直接使tmp的next等于newnode

(原本就定义了newnode的prev和next是NULL);

如果tmp后面 ,使原本ttmp的下一个的前向指针指向newnode 同时使 tmp 的后向指针指向newnode。

即:

if(tmp->next)

{

tmp->next->prev=newnode

}

tmp->next=newnode;

pos和clen相同就是尾插。

.h

#ifndef DOULINK_H
#define DOULINK_H
typedef struct{char name[32];char sex;int age;int score;
}DATATYPE;
typedef int (*PFUN)(DATATYPE*data,void* arg);
typedef struct node {DATATYPE data;struct node *next,*prev;
}DouLinkNode;typedef struct{DouLinkNode *head;int clen;
}DouLinkList;
typedef enum{DIR_FORWARD,DIR_BACKWARD}DIRECT;
DouLinkList* CreateDouLinkList();
int InsertHeadLinkList(DouLinkList *list, DATATYPE *data);
int ShowDouLinkList(DouLinkList *list,DIRECT direct);
int GetSizeDouLinkList(DouLinkList *list);
DouLinkNode *FindLinkList(DouLinkList *list, PFUN fun,void* arg);
int RevertDouLinkList(DouLinkList *list);
int DeleteLinkList(DouLinkList *list, PFUN fun,void* arg);
int IsEmptyDouLinkList(DouLinkList *list);
int ModifyDouLinkList(DouLinkList *list,PFUN fun,void* arg,DATATYPE *data);
int DestroyDouLinkList(DouLinkList **list);
int InserPosDouLinkList(DouLinkList *list,DATATYPE *data,int pos);
#endif // DOULINK_H

.c

#include "doulink.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>DouLinkList *CreateDouLinkList()
{//DouLinkList dl ;DouLinkList* dl = (DouLinkList*)malloc(sizeof(DouLinkList));if(NULL == dl){perror("CreateDouLinkList malloc");//exit(1);return NULL;}dl->head =NULL;dl->clen = 0 ;return dl;
}int InsertHeadLinkList(DouLinkList *list, DATATYPE *data)
{DouLinkNode*newnode = malloc(sizeof(DouLinkNode));if(NULL == newnode){perror("InsertHeadLinkList malloc");return 1;}memcpy(&newnode->data,data,sizeof(DATATYPE));newnode->next = NULL;newnode->prev= NULL;if(0==list->clen)//empty{list->head = newnode;}else{newnode->next = list->head;list->head->prev = newnode;list->head = newnode;}list->clen++;return 0;}int ShowDouLinkList(DouLinkList *list, DIRECT direct)
{int i = 0 ;DouLinkNode* tmp = list->head;if(direct==DIR_FORWARD){for(i=0;i<GetSizeDouLinkList(list);i++){printf("%s %c %d %d\n",tmp->data.name,tmp->data.sex,tmp->data.age,tmp->data.score);tmp=tmp->next;}}else{while(tmp->next){tmp=tmp->next;}for(i=0;i<GetSizeDouLinkList(list);i++){printf("%s %c %d %d\n",tmp->data.name,tmp->data.sex,tmp->data.age,tmp->data.score);tmp=tmp->prev;}}return 0;
}int GetSizeDouLinkList(DouLinkList *list)
{return list->clen;
}DouLinkNode *FindLinkList(DouLinkList *list, PFUN fun, void *arg)
{DouLinkNode* tmp = list->head;int size = GetSizeDouLinkList(list);int i =  0;for(i = 0 ;i<size;i++){//if(0==strcmp(tmp->data.name))if(fun(&tmp->data,arg)){return tmp;}tmp= tmp->next;}return NULL;
}int RevertDouLinkList(DouLinkList *list)
{int size = GetSizeDouLinkList(list);if(size<2){return 0;}DouLinkNode* prev= NULL;DouLinkNode* tmp = list->head;DouLinkNode*next= tmp->next;while(1){tmp->next = prev;tmp->prev = next;prev= tmp;tmp = next;if(NULL == tmp){break;}next =next->next;}list->head = prev;return 0;
}int DeleteLinkList(DouLinkList *list, PFUN fun, void *arg)
{if(NULL == list){fprintf(stderr,"DouLinkList is null");return 1;}if(IsEmptyDouLinkList(list)){fprintf(stderr,"DouLinkList is empty");return 1;}DouLinkNode* ret = FindLinkList(list,fun,arg);if(NULL==ret){fprintf(stderr,"DeleteLinkList error,cant find\n");return 1;}if(ret == list->head){list->head = ret->next;list->head->prev = NULL;}else{if(ret->next)ret->next->prev = ret->prev;ret->prev->next = ret->next;}free(ret);list->clen--;return 0;
}int IsEmptyDouLinkList(DouLinkList *list)
{return 0 == list->clen;
}int ModifyDouLinkList(DouLinkList *list, PFUN fun, void *arg, DATATYPE *data)
{DouLinkNode* ret = FindLinkList(list,fun,arg);if(NULL == ret){fprintf(stderr,"ModifyDouLinkList error,cant find\n");return 1;}memcpy(&ret->data,data,sizeof(DATATYPE));return 0;
}int DestroyDouLinkList(DouLinkList **list)
{DouLinkNode* tmp=(*list)->head;while(tmp){(*list)->head=(*list)->head->next;free(tmp);tmp = (*list)->head;}free(*list);(*list)= NULL;return 0;
}int InserPosDouLinkList(DouLinkList *list, DATATYPE *data,int pos)
{if(pos<0 ||pos>GetSizeDouLinkList(list)){fprintf(stderr,"InserPosDouLinkList error,index error\n");return 1;}if(IsEmptyDouLinkList(list) || 0 == pos){return InsertHeadLinkList(list,data);}else{DouLinkNode* tmp = list->head;tmp= list->head;DouLinkNode* newnode = (DouLinkNode*)malloc(sizeof(DouLinkNode));if(NULL == newnode){perror("InserPosDouLinkList malloc");return 1;}memcpy(&newnode->data,data,sizeof(DATATYPE));newnode->prev = NULL;newnode->next = NULL;int i = pos-1;while(i--){tmp=tmp->next;}newnode ->prev = tmp;newnode->next = tmp->next;if(tmp->next){tmp->next->prev = newnode;}tmp->next = newnode;}list->clen++;return 0;
}

man.c

#include <stdio.h>
#include "doulink.h"
#include <string.h>
int findbyname(DATATYPE*data,void* arg)
{return (0 == strcmp(data->name,(char*)arg));
}
int findbyage(DATATYPE*data,void* arg)
{return data->age == *(int*)arg;
}
int main()
{DATATYPE data[5]={{"zhangsan",'m',20,70},{"lisi",'f',21,60},{"wangmazi",'m',25,80},{"liubei",'f',30,85},{"caocao",'f',40,90},};DouLinkList* dl = CreateDouLinkList();InsertHeadLinkList(dl,&data[0]);InsertHeadLinkList(dl,&data[1]);InsertHeadLinkList(dl,&data[2]);ShowDouLinkList(dl,DIR_FORWARD);printf("-------------back---------------\n");ShowDouLinkList(dl,DIR_BACKWARD);printf("-------------find---------------\n");//    char want_name[]="lisi";//    //DouLinkNode* tmp = FindLinkList(dl,findbyname,want_name);//    int want_age = 25;//    DouLinkNode* tmp = FindLinkList(dl,findbyage,&want_age);//    if(NULL == tmp)//    {//        printf("can't find person ,name:%s\n",want_name);//    }//    else//    {//        printf("%s:%d\n",tmp->data.name,tmp->data.score);//    }//    RevertDouLinkList(dl);//    printf("-------------rev---------------\n");//    ShowDouLinkList(dl,DIR_FORWARD);//    DeleteLinkList(dl,findbyname,"lisi");//    printf("-------------del forware---------------\n");//    ShowDouLinkList(dl,DIR_FORWARD);//    printf("-------------back---------------\n");//    ShowDouLinkList(dl,DIR_BACKWARD);//    ModifyDouLinkList(dl,findbyname,"zhangsan",&data[3]);//    printf("-------------modify---------------\n");//    ShowDouLinkList(dl,DIR_FORWARD);InserPosDouLinkList(dl,&data[3],3);printf("-------------pos---------------\n");ShowDouLinkList(dl,DIR_FORWARD);printf("-------------back---------------\n");ShowDouLinkList(dl,DIR_BACKWARD);DestroyDouLinkList(&dl);printf("Hello World!\n");return 0;
}

顺序表和链表 优缺点
   
      

顺序表(Array)

优点

  1. 随机访问:顺序表支持通过索引快速访问任意位置的元素,时间复杂度为O(1)。
  2. 存储密度高:顺序表在物理存储上是连续的,存储密度大(即存储空间利用率高,因为不需要额外存储指针等信息)。
  3. 缓存友好:顺序表的数据在物理上连续存储,因此可能更好地利用CPU缓存,提高访问效率。

缺点

  1. 插入和删除操作成本高:在顺序表的中间或开始位置插入或删除元素时,需要移动大量的元素来保持数据的连续性,时间复杂度为O(n)。
  2. 扩容问题:当顺序表的容量不足以存储更多元素时,需要进行扩容操作,这涉及到申请新的内存空间、复制原有数据到新空间等步骤,可能会比较耗时。
  3. 空间利用率可能不高:在顺序表中,如果预留的空间过大,但实际存储的元素较少,会导致空间浪费;如果预留的空间过小,又需要频繁扩容,影响效率。

链表(LinkedList)

优点

  1. 插入和删除操作灵活:链表在插入和删除元素时,只需要改变指针的指向,不需要移动大量的元素,时间复杂度为O(1)(在已知位置进行操作时)。这使得链表非常适合于频繁插入和删除操作的场景。
  2. 动态分配内存:链表中的节点可以动态地申请和释放内存,使得链表的大小可以根据需要动态变化,无需担心空间浪费或扩容问题。

缺点

  1. 访问元素效率低:访问链表中的元素需要从头节点开始遍历,直到找到所需的元素,时间复杂度为O(n)。
  2. 空间利用率相对较低:链表中每个节点除了存储数据本身外,还需要额外存储指针(或引用)信息,这增加了存储空间的开销。
  3. 缓存不友好:由于链表的节点在物理上不一定连续存储,因此可能无法有效地利用CPU缓存,导致访问效率下降。

     
            
    循环链表     

 简单的来说,就是将原来单链表中最有一个元素的next指针指向第一个元素或头结点,链表就成了一个环,头尾相连,就成了循环链表。circultlar linker list.
        
        注意非空表,和空表。多数会加入头结点。

        原来结束的条件是        

p->next != NULL ------->>>>> p-next != Head   
或者写成 指定长度clen;        

 双向链表
    double link list
 
    typedef struct DulNode
    {
    
        ElemType date;
        struct DulNode *pri;
        sturct DulNode *next;
    }DulNode,*DuLinkList;
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/49822.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

四、单线程多路IO复用+多线程业务工作池

文章目录 一、前言1 编译方法 二、单线程多路IO复用多线程业务工作池结构三、重写Client_Context类四、编写Server类 一、前言 我们以及讲完单线程多路IO复用 以及任务调度与执行的C线程池&#xff0c;接下来我们就给他结合起来。 由于项目变大&#xff0c;尝试解耦项目&#…

47.简易电压表的设计与验证(2)

&#xff08;1&#xff09;Verilog 代码&#xff1a; module adc_collect(input clk ,input reset_n ,input [7:0] adc_data ,output clk_adc );wire clk_adc_a ;…

提交高通量测序处理数据到 GEO --- 操作流程

❝ 写在前面 由于最近在提交课题数据到 NCBI 数据库&#xff0c;整理了相关笔记。本着自己学习、分享他人的态度&#xff0c;分享学习笔记&#xff0c;希望能对大家有所帮助。推荐先按顺序阅读往期内容&#xff1a; 1. 提交高通量测序数据到 GEO --- 说明书 2. 提交高通量测序原…

基于机器学习的二手房价格分析与预测设计与实现

概述 随着西安房地产市场的不断发展和变化&#xff0c;对二手房价格的准确预测变得至关重要。本研究旨在利用机器学习技术对西安市二手房价格进行深入分析与预测&#xff0c;通过对原始数据进行数据预处理和特征提取&#xff0c;以构建有效的预测模型。通过数据分析和可视化&a…

LabVIEW学习-LabVIEW处理带分隔符的字符串从而获取数据

带分隔符的字符串很好处理&#xff0c;只需要使用"分隔符字符串至一维字符串数组"函数或者"一维字符串数组至分隔符字符串"函数就可以很轻松地处理带分隔符地字符串。 这两个函数所在的位置为&#xff1a; 函数选板->字符串->附加字符串函数->分…

第13周 简历职位功能开发与Zookeeper实战

第13周 简历职位功能开发与Zookeeper实战 本章概述1. Mysql8窗口函数over使用1.1 演示表结构与数据1.2 案例1:获取男女总分数1.3 案例2****************************************************************************************本章概述 1. Mysql8窗口函数over使用 参考案例…

从零开始学习机器学习,掌握AI未来的关键!

从零开始学习机器学习 1. 介绍1.1 人工智能&#xff08;AI&#xff09;概述1.2 机器学习在人工智能中的应用1.3 机器学习基础概念 2. 监督学习2.1 什么是监督学习2.2 回归分析2.3 分类问题2.4 模型评估和选择 3. 无监督学习3.1 什么是无监督学习3.2 聚类算法3.3 降维技术 4. 深…

Elasticsearch 7.x入门学习-Java API操作

1 创建项目 在idea开发工具中创建Maven项目 修改 pom 文件&#xff0c;增加 Maven 依赖关系 <dependencies><dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>7.8.0</versi…

C语言 | Leetcode C语言题解之第268题丢失的数字

题目&#xff1a; 题解&#xff1a; /* 求和运算 */ /* 对[0,n]求和, 减去数组每个元素, 得出丢失的元素 */ int missingNumber(int* nums, int numsSize){int i;int sum numsSize;for (i 0; i < numsSize; i) {sum i - nums[i];}return…

每天五分钟计算机视觉:目标检测模型从RCNN到Fast R-CNN的进化

本文重点 前面的课程中,我们学习了RCNN算法,但是RCNN算法有些慢,然后又有了基于RCNN的Fast-RCNN,Fast R-CNN是一种深度学习模型,主要用于目标检测任务,尤其在图像中物体的识别和定位方面表现出色。它是R-CNN系列算法的一个重要改进版本,旨在解决R-CNN中计算量大、速度慢…

python-阶乘和(赛氪OJ)

题目描述 求Sn​1!2!3!4!5!⋯n!的值&#xff0c;其中 &#x1d45b;n 是一个数字。输入格式&#xff1a; 输入一个整数 n。输出格式&#xff1a; 输出对应的 Sn​。 样例输入输出样例输入 5样例输出 153数据范围 对于 100% 的数据&#xff0c;保证1≤n≤20。来源/分类&#xff…

接口自动化测试框架实战-4-日志方法封装

上一小节我们讲解了文件读写方法的封装方法&#xff0c;本小节我们完成一下框架日志的封装方法。 首先我们讲解一下日志封装和日志记录有哪些用处&#xff1f; 更加方便的设置日志的格式和输出方式全局方法可以各个类/函数中都能统一调用分类记录接口用例执行日志&#xff0c…

【CPS出版】2024年智能计算与数据分析国际学术会议(ICDA 2024,9月6日-8)

为探讨数据科学和计算智能领域的关键问题&#xff0c;促进相关交流&#xff0c;2024年智能计算与数据分析国际学术会议&#xff08;ICDA 2024)将于2024年9月6日-8日在中国青岛召开。 本届会议拟邀请数据分析和计算智能领域的顶级专家、学者和产业界优秀人才&#xff0c;围绕当前…

【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !

目录 C语言中指针的大小1. 指针大小的基本概念1.1 32位系统1.2 64位系统 2. 指针大小示例2.1 32位系统输出2.2 64位系统输出 3. 指针大小与数据类型无关示例输出示例 4. 跨平台的指针大小示例输出示例 5. 关键点总结5.1 指针大小与平台关系5.2 跨平台编程注意事项 6. 指针大小示…

【QAC】Dashboard服务端如何配置

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 解决Dashboard服务端如何配置的问题。 2、 问题场景 客户想使用Dashboard&#xff0c;Dashboard服务端如何配置。 3、软硬件环境 1、软件版本&#xff1a;HelixQAC23.04 2、机器环境&#xff1a;Windows 64bit 3…

arthas在idea和docker中的应用

基于IDEA工具使用 1&#xff0c;安装arthas插件 安装之后重启&#xff0c;然后再代码区域右键如果可以看到如下菜单选项&#xff0c;则说明安装成功 2&#xff0c;pom文件中配置arthas相关jar包 <!-- https://mvnrepository.com/artifact/com.taobao.arthas/arthas-pack…

解决小程序web-view两个恶心问题

&#x1f9d1;‍&#x1f4bb; 写在开头 点赞 收藏 学会&#x1f923;&#x1f923;&#x1f923; 1.web-view覆盖层问题 问题由来 web-view 是一个 web 浏览器组件&#xff0c;可以用来承载网页的容器&#xff0c;会自动铺满整个页面。 所以这得多恶心。。。不仅铺满&…

机会性加密技术:网络安全的新趋势

在当今数字化时代&#xff0c;网络安全已成为各行各业不可忽视的重要议题。随着网络攻击手段的不断演进&#xff0c;传统的加密方式已难以满足复杂多变的安全需求。机会性加密技术&#xff08;Opportunistic Encryption&#xff0c;简称OE&#xff09;&#xff0c;作为一种新兴…

基于微信小程序的健康饮食系统/健康饮食管理系统

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的小程序应运而生&#xff0c;各行各业相继进入信息管理时代&…

[Vulnhub] Acid-Reloaded SQLI+图片数据隐写提取+Pkexec权限提升+Overlayfs权限提升

信息收集 IP AddressOpening Ports192.168.101.158TCP:22,33447 $ nmap -p- 192.168.101.158 --min-rate 1000 -sC -sV Not shown: 65534 closed tcp ports (conn-refused) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 6.7p1 Ubuntu 5ubuntu1.3 (Ubuntu Lin…