Linux C 数据结构---链表(单向链表)

 上一篇我们讲到了线性表,线性表就是数据元素都一一对应,除只有唯一的前驱,唯一的后继。

       线性表存储结构分为顺序存储、链式存储。

       顺序存储的优点:

       顺序存储的缺点:

       链表就是典型的链式存储,将线性表L = (a0,a1,a2,........an-1)中个元素分布在存储器的不同存储块,成为结点(Node),通过地址或指针建立他们之间的练习,所得到的存储结构为链表结构。表中元素ai的结点形式如下:

其中,结点的data域存放数据元素ai,而next域是一个指针,指向ai的直接后继a(i+1)所在的结点。于是,线性表L=(a0,a1,......an-1)的结构如图:

 

一、节点类型描述:

[cpp] view plaincopy
  1. typedef struct node_t  
  2. {  
  3.     data_t data; //节点的数据域  
  4.     struct node_t *next;//节点的后继指针域  
  5. }linknode_t,*linklist_t;  

也可这样表示:

[cpp] view plaincopy
  1. struct node_t  
  2. {  
  3.     data_t data;   
  4.     struct node_t *next;  
  5. }  
  6. typedef struct node_t linknode_t;  
  7. typedef struct node_t *linklist_t;  

若说明

linknode_t  A;

linklist_t p  = &A;

则结构变量A为所描述的节点,而指针变量P为指向此类型节点的指针(p的值为节点的地址);

这样看来 linknode_t  linklist_t 的作用是一样的,那为什么我们要定义两个数据类型(同一种)呢?主要为了代码的可读性,我们要求标识符要望文识义,便于理解;

1、linknode_t  *pnode  指向一个节点;

2、linklist_t list  指向一个整体


二、头结点 head

        我们在前篇提到的顺序存储线性表,如何表达一个空表{ },是通过list->last = -1来表现的,所谓的空表就是数据域为NULL,而我们的链表有数据域和指针域,我们如何表现空链表呢?这时,就引入了头结点的概念,头结点和其他节点数据类型一样,只是数据域为NULL,head->next = NULL,下面我们看一个创建空链表的函数,如何利用头结点来创建一个空链表:

[cpp] view plaincopy
  1. linklist_t CreateEmptyLinklist()  
  2. {  
  3.     linklist_t list;  
  4.   
  5.     list = (linklist_t)malloc(sizeof(linknode_t));  
  6.     if (NULL != list) {  
  7.         list->next = NULL;  
  8.     }  
  9.     return list;  
  10. }  

只要头结点,链表就还在!

 

三、链表基本运算的相关算法

         链表的运算除了上面的创建空链表,还有数据的插入,删除,查找等函数,链表的运算有各种实现方法,如何写出一个高效的,封装性较好的函数是我们要考虑的,比如数据插入函数,我们就要尽可能考虑所有能出现的结果,比如:1)如果需插入数据的链表是个空表;2)所插入的位置超过了链表的长度;如果我们的函数能包含所有能出现的情况,不仅能大大提高我们的开发效率,也会减少代码的错误率。下面,我们来看看下面的这个链表的插入函数的实现:

[cpp] view plaincopy
  1. int InsertLinklist(linklist_t list, int at, data_t x)  
  2. {  
  3.     linknode_t *node_prev, *node_at, *node_new;  
  4.     int pos_at;  
  5.     int found = 0;  
  6.   
  7.     if (NULL == list) return -1;  
  8.   
  9.     /* at must >= 0  */  
  10.     if (at < 0) return -1;  
  11.       
  12.     /*第一步、分配空间*/  
  13.     node_new = malloc(sizeof(linknode_t));  
  14.     if (NULL == node_new)   
  15.     {  
  16.         return -1;  
  17.     }  
  18.     node_new->data = x; /* assigned value */  
  19.     node_new->next = NULL; /*节点如果插入超过链表长度的位置,会接到尾节点后面,这样,node_new成了尾节点,node_new->next = NULL */  
  20.   
  21.     /*第二步、定位*/  
  22.     node_prev = list;//跟随指针,帮助我们更好的定位  
  23.     node_at = list->next; //遍历指针  
  24.     pos_at = 0;  
  25.     while (NULL != node_at)   
  26.     {  
  27.         if (pos_at == at)  
  28.         {  
  29.             found = 1; //找到正确的位置,跳出循环  
  30.             break;            
  31.         }  
  32.   
  33.         /* move to the next pos_at */  
  34.         node_prev = node_at; //跟随指针先跳到遍历指针的位置  
  35.         node_at = node_at->next;//遍历指针跳到下一个节点的位置  
  36.         pos_at++;  
  37.     }  
  38.   
  39.     /*第三步、插入*/    
  40.     if (found)   
  41.     {  
  42.         /* found = 1,找到正确的位置,插入  */  
  43.         node_new->next = node_at;//插入的节点next指向node_at  
  44.         node_prev->next = node_new;//插入节点的前一个节点  
  45.     }   
  46.     else   
  47.     {  
  48.         /*若是没找到正确的位置,即所插入位置超越了链表的长度,则接到尾节点的后面,同样,这样适用于{ }即空链表,这样我们可以建立一个空链表,利用这个函数,实现链表的初始化*/  
  49.         node_prev->next = node_new;  
  50.     }  
  51.       

这个插入函数可利用性就非常高。

 

下面讲一个完整链表代码贴出:

listlink.h

[cpp] view plaincopy
  1. #ifndef _LNK_LIST_H_  
  2. #define _LNK_LIST_H_  
  3.   
  4. typedef int data_t;  
  5.   
  6. typedef struct node_t {  
  7.     data_t data;  
  8.     struct node_t *next;  
  9. } linknode_t, *linklist_t;  
  10.   
  11. linklist_t CreateEmptyLinklist();  
  12.   
  13. void DestroyLinklist(linklist_t list);  
  14.   
  15. void ClearLinklist(linklist_t list);  
  16.   
  17. int EmptyLinklist(linklist_t list);  
  18.   
  19. int LengthLinklist(linklist_t list);  
  20.   
  21. int GetLinklist(linklist_t list, int at, data_t *x);  
  22.   
  23. int SetLinklist(linklist_t list, int at, data_t x);  
  24.   
  25. int InsertLinklist(linklist_t list, int at, data_t x);  
  26.   
  27. int DeleteLinklist(linklist_t list, int at);  
  28.   
  29. linklist_t ReverseLinklist(linklist_t list);  
  30.   
  31. #endif /* _LNK_LIST_H_ */  

linklist.c

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include "linklist.h"  
  4.   
  5. linklist_t CreateEmptyLinklist()  
  6. {  
  7.     linklist_t list;  
  8.     list = (linklist_t)malloc(sizeof(linknode_t));  
  9.   
  10.     if (NULL != list) {  
  11.         list->next = NULL;  
  12.     }  
  13.   
  14.     return list;  
  15. }  
  16.   
  17. void DestroyLinklist(linklist_t list)  
  18. {  
  19.     if (NULL != list) {  
  20.         ClearLinklist(list);  
  21.         free(list);  
  22.     }  
  23. }  
  24.   
  25. void ClearLinklist(linklist_t list)  
  26. {  
  27.     linknode_t *node; /* pointer to the node to be removed */  
  28.     if (NULL == list) return;  
  29.   
  30.     while (NULL != list->next) {  
  31.         node = list->next;  
  32.         list->next = node->next;  
  33.         free(node);  
  34.     }  
  35.     return;  
  36. }  
  37.   
  38. int LengthLinklist(linklist_t list)  
  39. {  
  40.     int len = 0;  
  41.     linknode_t *node; //iterate pointer  
  42.   
  43.     if (NULL == list) return -1;  
  44.   
  45.     node = list->next; // node points to the first data node  
  46.     while (NULL != node) {  
  47.         len++;  
  48.         node = node->next;  
  49.     }  
  50.     return len;  
  51. }  
  52.   
  53. int EmptyLinklist(linklist_t list)  
  54. {  
  55.     if (NULL != list) {  
  56.         if (NULL == list->next) {  
  57.             return 1;  
  58.         } else {  
  59.             return 0;  
  60.         }  
  61.     } else {  
  62.         return -1;  
  63.     }  
  64. }  
  65.   
  66. int GetLinklist(linklist_t list, int at, data_t *x)  
  67. {  
  68.     linknode_t *node;   /* used for iteration */  
  69.     int pos;        /* used for iteration and compare with */  
  70.   
  71.     if (NULL == list) return -1;  
  72.     /* at must >= 0 */  
  73.     if (at < 0) return -1;  
  74.     /* start from the first element */  
  75.     node = list->next;  
  76.     pos = 0;  
  77.     while (NULL != node) {  
  78.         if (at == pos) {  
  79.             if (NULL != x) {  
  80.                 *x = node->data;  
  81.             }  
  82.             return 0;             
  83.         }  
  84.         /* move to the next */  
  85.         node = node->next;  
  86.         pos++;  
  87.     }  
  88.     return -1;  
  89. }  
  90.   
  91.   
  92.   
  93. int SetLinklist(linklist_t list, int at, data_t x)  
  94. {  
  95.     linknode_t *node; /* used for iteration */  
  96.     int pos;  
  97.     int found = 0;  
  98.   
  99.     if (!list) return -1;  
  100.     /* at must >= 0 */  
  101.     if (at < 0) return -1;  
  102.     /* start from the first element */  
  103.     node = list->next;  
  104.     pos = 0;  
  105.     while (NULL != node) {  
  106.         if (at == pos) {   
  107.             found = 1; /* found the position */  
  108.             node->data = x;  
  109.             break;            
  110.         }  
  111.         /* move to the next */  
  112.         node = node->next;  
  113.         pos++;  
  114.     }  
  115.     if (1 == found) {  
  116.         return 0;  
  117.     } else {  
  118.         return -1;  
  119.     }  
  120. }  
  121.   
  122. int InsertLinklist(linklist_t list, int at, data_t x)  
  123. {  
  124.     /*  
  125.      * node_at and pos_at are used to locate the position of node_at. 
  126.      * node_prev follows the node_at and always points to previous node  
  127.      *  of node_at. 
  128.      * node_new is used to point to the new node to be inserted. 
  129.      */  
  130.     linknode_t  *node_prev, *node_at, *node_new;  
  131.     int     pos_at;  
  132.     int         found = 0;  
  133.   
  134.     if (NULL == list) return -1;  
  135.   
  136.     /* at must >= 0 */  
  137.     if (at < 0) return -1;  
  138.   
  139.     node_new = malloc(sizeof(linknode_t));  
  140.     if (NULL == node_new) {  
  141.         return -1;  
  142.     }  
  143.     node_new->data = x; /* assigned value */  
  144.     node_new->next = NULL;  
  145.   
  146.     node_prev = list;  
  147.     node_at = list->next;  
  148.     pos_at = 0;  
  149.     while (NULL != node_at) {  
  150.         if (pos_at == at) {  
  151.             /*  
  152.              * found the node 'at' 
  153.              */   
  154.             found = 1;  
  155.             break;            
  156.         }  
  157.         /* move to the next pos_at */  
  158.         node_prev = node_at;  
  159.         node_at = node_at->next;  
  160.         pos_at++;  
  161.     }  
  162.       
  163.     if (found) {  
  164.         /* insert */  
  165.         node_new->next = node_at;  
  166.         node_prev->next = node_new;  
  167.     } else {  
  168.         /*  
  169.          * If not found, means the provided "at" 
  170.          * exceeds the upper limit of the list, just  
  171.          * append the new node to the end of the list. 
  172.          */  
  173.         node_prev->next = node_new;  
  174.     }  
  175.     return 0;  
  176. }  
  177.   
  178. int DeleteLinklist(linklist_t list, int at)  
  179. {  
  180.     /*  
  181.      * node_at and pos_at are used to locate the position of node_at. 
  182.      * node_prev follows the node_at and always points to previous node  
  183.      *  of node_at. 
  184.      */  
  185.   
  186.     linknode_t  *node_prev, *node_at;  
  187.     int     pos_at;  
  188.     int         found = 0;  
  189.   
  190.     if (!list) return -1;  
  191.     /* at must >= 0 */  
  192.     if (at < 0) return -1;  
  193.   
  194.     node_prev = list;  
  195.     node_at = list->next;  
  196.     pos_at = 0;   
  197.   
  198.     while (NULL != node_at) {  
  199.         if (pos_at == at) {  
  200.             /*  
  201.              * found the node 'at' 
  202.              */   
  203.             found = 1;  
  204.             break;            
  205.         }  
  206.         /* move to the next pos_at */  
  207.         node_prev = node_at;  
  208.         node_at = node_at->next;  
  209.         pos_at++;  
  210.     }  
  211.     if (found) {  
  212.         /* remove */  
  213.         node_prev->next = node_at->next;  
  214.         free(node_at);  
  215.         return  0;  
  216.     } else {  
  217.         return -1;  
  218.     }  
  219. }  
  220.   
  221. linklist_t ReverseLinklist(linklist_t list)  
  222. {  
  223.     linknode_t *node;   /* iterator */  
  224.     linknode_t *node_prev;  /* previous node of iterator */  
  225.     linknode_t *node_next;  /* next node of iterator,  
  226.                  * used to backup next of iterator  
  227.                  */  
  228.     if (NULL == list) return NULL;  
  229.     node_prev = NULL;  
  230.     node = list->next;  
  231.     while (NULL != node) {  
  232.         /* 
  233.          * step1: backup node->next 
  234.          * due to the next of iterator will be 
  235.          * modified in step2 
  236.          */  
  237.         node_next = node->next;  
  238.         /*  
  239.          * when iterator reaches the last node  
  240.          * of original list, make the list head 
  241.          * point to the last node, so the original 
  242.          * last one becomes the first one. 
  243.          */  
  244.   
  245.         if (NULL == node_next) {  
  246.             list->next = node;  
  247.         }  
  248.   
  249.         /*  
  250.          * step2: reverse the linkage between nodes 
  251.          * make the node pointer to the previous node, 
  252.          * not the next node 
  253.          */       
  254.         node->next = node_prev;        
  255.         /*  
  256.          * step3: move forward  
  257.          */  
  258.   
  259.         node_prev = node;  
  260.         node = node_next;  
  261.     }  
  262.     return list;  
  263. }  

main.c

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include "linklist.h"  
  4.   
  5. int main()  
  6. {  
  7.     int i;  
  8.     data_t x;  
  9.     linklist_t p;  
  10.     p = CreateEmptyLinklist();  
  11.     data_t a[10] = {1,3,5,7,9,11,13,15,17,19};  
  12.   
  13.     for(i = 0;i < 10;i++)  
  14.     {  
  15.         InsertLinklist(p,i,a[i]);  
  16.     }  
  17.   
  18.     ReverseLinklist(p);  
  19.     printf("The length of the list is:%d\n",LengthLinklist(p));  
  20.       
  21.     GetLinklist(p,4,&x);  
  22.     printf("The NO.4 of this list is:%d\n",x);  
  23.   
  24.     SetLinklist(p,4,100);  
  25.     GetLinklist(p,4,&x);  
  26.     printf("After updating!The No.4 0f this list is:%d\n",x);  
  27.   
  28.     DeleteLinklist(p,4);  
  29.     printf("After updating!The length of the list is:%d\n",LengthLinklist(p));  
  30.     GetLinklist(p,4,&x);  
  31.     printf("After updating!The No.4 0f this list is:%d\n",x);  
  32.   
  33.     ReverseLinklist(p);  
  34.       
  35.     ClearLinklist(p);  
  36.     if(EmptyLinklist(p))  
  37.         printf("This list is empty!\n");  
  38.     DestroyLinklist(p);  
  39.     printf("This list is destroyed!\n");  
  40.   
  41.     return 0;  
  42.       
  43. }  

执行结果如下:

[cpp] view plaincopy
  1. fs@ubuntu:~/qiang/list/list2$ ./Test  
  2. The length of the list is:10  
  3. The NO.4 of this list is:11  
  4. After updating!The No.4 0f this list is:100  
  5. After updating!The length of the list is:9  
  6. After updating!The No.4 0f this list is:9  
  7. This list is empty!  
  8. This list is destroyed!  

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

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

相关文章

前端学PHP之文件操作(认真读读)

前面的话 在程序运行时&#xff0c;程序本身和数据一般都存在内存中&#xff0c;当程序运行结束后&#xff0c;存放在内存中的数据被释放。如果需要长期保存程序运行所需的原始数据&#xff0c;或程序运行产生的结果&#xff0c;就需要把数据存储在文件或数据库。一般地&#x…

java 定时任务(三):cron表达式

From: https://www.cnblogs.com/sawyerlsy/p/7208321.html 一、完整的cron表达式由7位以空格分隔的时间元素组成&#xff0c;从左到右分别为&#xff1a;秒、分、时、日期、月份、星期几、年份。其中需要注意的有以下几点&#xff1a; 1. spring 4.x 的spring task中只支持前6种…

我为什么要立刻放弃 React 而使用 Vue?

From: https://baijiahao.baidu.com/s?id1607323518011007619&wfrspider&forpc CSDN 发布时间&#xff1a;18-07-29 19:28 现在&#xff0c;Vue.js 在 Github 上得到的星星数已经超过了 React。这个框架的流行度在不断增长&#xff0c;由于它并没有像 Facebok&#…

本地同时修改2个版本

为什么80%的码农都做不了架构师&#xff1f;>>> 昨天讨论后我又想了想&#xff0c;你主要的需求是想在本地同时修改2个版本&#xff0c;用分支也可以做到&#xff0c;方法如下 上图是库的目录结构&#xff0c;比如Codes上做了个分支b1&#xff0c;想同时在本地编辑…

Linux C 内存管理

提到C语言&#xff0c;我们知道C语言和其他高级语言的最大的区别就是C语言是要操作内存的&#xff01; 我们需要知道——变量&#xff0c;其实是内存地址的一个抽像名字罢了。在静态编译的程序中&#xff0c;所有的变量名都会在编译时被转成内存地址。机器是不知道我们取的名字…

CSDN并购博客园遐想

我要打“假想”&#xff0c;打成了“遐想”&#xff0c;不过确实这篇文章属于我个人YY出来的。主要晚上写博客&#xff0c;用live writer发布好多次都不成功&#xff0c;然后用浏览器访问博客园首页&#xff0c;出现了下面画面。估计很多人都很熟悉这个界面&#xff0c;因为阿里…

android 多线程概述

android多线程&#xff0c;一直是一个麻烦的事情&#xff0c;要掌握它的本质&#xff0c;我们需要搞清楚一个问题&#xff0c;linux多线程的本质。 我们这篇文章&#xff0c;来讨论以下的议程&#xff1a; 了解linux的历程&#xff0c;了解android的异步任务机制&#xff0c;了…

Linux 进程间通讯详解一

进程间的通讯 两台主机间的进程通讯 --socket一台主机间的进程通讯 --管道&#xff08;匿名管道&#xff0c;有名管道&#xff09; --System V进程间通信&#xff08;IPC&#xff09;包括System V消息队列&#xff0c;System V信号量&#xff0c;System V共享内存 --socket 进程…

Linux C 函数指针应用---回调函数

&#xff08;这里引用了知乎上一些知友的回答&#xff0c;感觉不错&#xff0c;有助于理解&#xff0c;这里引用作为借鉴&#xff0c;如有冒犯&#xff0c;烦请告知&#xff09; 我们先来回顾一下函数指针&#xff0c;函数指针是专门用来存放函数地址的指针&#xff0c;函数地址…

laravel+vue开发环境搭建

From: https://www.jianshu.com/p/1c2cc11ba46f 描述 最近通过laravel在公司做了一些项目&#xff0c;但本身前端出身的我&#xff0c;总是感觉lphp开发过程中,前端写好页面&#xff0c;然后后端还需要再套blade模板&#xff0c;感觉这样开发效率太慢&#xff0c;太low。于是自…

GC Blocks Lost等待事件

在Oracle RAC环境中&#xff0c;无论我们从AWR自动负载性能报告、Statspack或者Grid Control中都可以找到Oracle数据库软件所收集的全局缓存工作负载统计信息(global cache work load statistics)&#xff1b;其中就包含了全局缓存块丢失(Global cache lost blocks)的统计信息(…

WCF简单教程(5) 用IIS做Host

第五篇&#xff1a;用IIS做Host之前几篇的Demo中&#xff0c;我们一直在用控制台程序做Server&#xff0c;今天换IIS来做Host&#xff0c;在Web Application中添加WCF的服务。其实在Web Application中添加WCF服务是最简单的&#xff0c;“新建项”中有专用的“WCF服务”&#x…

黑苹果折腾记

From: https://fishedee.com/2018/10/04/%E9%BB%91%E8%8B%B9%E6%9E%9C%E6%8A%98%E8%85%BE%E8%AE%B0/ 1 概述 黑苹果折腾记&#xff0c;原来的Macbook Pro已经不太好用了&#xff0c;运行编译时就开始风扇呼呼声的响&#xff0c;我只有想办法将苹果安装上现有的台式机上了。 类…

解决爬虫中文乱码问题

解决爬虫中文乱码问题 今天群里有个人反映某个网址爬出来的网页源代码出现中文乱码&#xff0c;我研究了半天&#xff0c;终于找到了解决方法。 一开始&#xff0c;我是这样做的&#xff1a; import requestsurl http://search.51job.com/jobsearch/search_result.php?fromJs…

一夜暴富之前的漫漫长路

一夜暴富之前的漫漫长路发布于&#xff1a;2013-08-05 09:50阅读数&#xff1a;987那你现在在做什么&#xff1f; 唉&#xff0c;我讨厌这个问题。 事实上&#xff0c;我正在努力做一个新的项目&#xff0c;但没有取得任何的进展。 但是&#xff0c;我并没有抱怨什么&#xff0…

java开发过程中,报错Dangling meta character '*' near index 0,解决办法

From: https://blog.csdn.net/zhouzhiwengang/article/details/53493810 1、split方法转化字符串为数组&#xff1a; String[] strPicArr map.get("hw_pic").toString().split("*"); 报错&#xff1a; java.util.regex.PatternSyntaxException: Dangling…

演示:Linux工程环境应用实训(防火墙、NAT、静态路由)详细配步骤

各位童鞋注意&#xff1a;该实验完成可以使用GNS3与4虚拟机进行桥接&#xff0c;然后在一台物理计算机上完成&#xff0c;不虽要去拿真正的4台服务器或者交换机路由器来连成一个网络&#xff0c;现在大家都使用网络仿真教学与实验&#xff01;Linux工程环境应用实训&#xff08…

Linux架构

Linux架构 作者&#xff1a;Vamei 出处&#xff1a;http://www.cnblogs.com/vamei 欢迎转载&#xff0c;也请保留这段声明。谢谢&#xff01; 我以下图为基础&#xff0c;说明Linux的架构(architecture)。(该图参考《Advanced Programming in Unix Environment》) 最内层是硬件…

Linux C学习--getline()函数

getline()函数是什么&#xff1f;百度百科这样解释&#xff1a; getline不是C库函数&#xff0c;而是C库函数。它会生成一个包含一串从输入流读入的字符的字符串&#xff0c;直到以下情况发生会导致生成的此字符串结束。1&#xff09;到文件结束&#xff0c;2&#xff09;遇到函…

Mac10.14.4 独立显卡 影驰GTX 760 4GB成功驱动

先了解下这篇文章: https://blog.csdn.net/JoeBlackzqq/article/details/39612351 这是我的硬件配置! 当初装10.14.4时, 看网上文章说我的独显是无法驱动的,所以当时用的是我的核显(CPU i7-4770k HD4600)装上的. 但是在系统稳定的跑了个把月后,不知什么原因(一阵电流声), 我…