1.链表认知

一场病,断了好久。这几天算是基本没什么问题了。是时候继续了。

链表我想可以认为是,点到线的过程。

一个个点就是一个个链表的节点,以特定的顺序组合或链接后,行成了一条线,即链表。所以添加,删除一个点是相对较容易的(因为可以动态的追加,删除节点),但是查找某个点相对较麻烦(数组中只需要a[i]即可取得数据,链表则需要遍历)。所以,对于未知大小长度的数据来说,具有相当的优势。但已知数据量来说,数组可能更好一些。

单链表

单链表(通常简称为链表)由各个元素之间通过一个指针彼此链接起来而组成。每个元素包含两部分:数据成员和一个称为nexr的指针。通过采用这种二成员结构,将每个元素的next指针设置为指向其后面的元素。最后一个元素的next指针置为NUL,简单地表示链表的尾端。链表开始处的元素是“头”,链表末尾的元素称为“尾。

简单来说,火车是最好理解的链表了。车头就是“头”,每节车厢里面装的人救赎数据,车厢后面连接下一个车厢的铁栓就是next指针。

单链表代码实现

#include<stdio.h>
#include<stdlib.h>
#include<string.h>typedef struct ListElmt   //定义节点
{void *data;struct ListElmt  *next;
};typedef struct List  //定义链表
{int size;int(*match)(const void *key1, const void *key2); //构造函数void(*destroy)(void *data);  //析构函数ListElmt *head;ListElmt *tail;
};void list_init(List *list, void(*destroy)(void *data));     //新建链表
void list_destroy(List *list);                             //移除链表中的元素
void list_size(List *list, void (*destroy)(void *data));    //链表长度
int list_ins_next(List *list, ListElmt *element, const void *data);  //尾插
int list_rem_next(List *list, ListElmt *element, void **data);   //移除#define list_is_head(list,element) ((element) == (list)->head ? 1:0)
#define list_is_tail(element) ((element)->next == NULL ? 1:0)//新建链表
void list_init(List *list, void(*destroy)(void *data))
{list->size = 0;list->destroy = destroy;list->head = NULL;list->tail = NULL;return;
}//销毁链表
void list_destroy(List *list)
{void *data;while (list->size > 0){if (list_rem_next(list, NULL, (void **)&data) == 0 && list->destroy != NULL){list->destroy(data); //循环删除元素}}memset(list, 0, sizeof(List));return;
}int list_ins_next(List *list, ListElmt *element, const void *data)
{ListElmt *new_element;if ((new_element = (ListElmt *)malloc(sizeof(ListElmt))) == NULL)return -1;new_element->data = (void *)data;if (element == NULL){if (list->size == 0){list->tail = new_element;}new_element->next = list->head;list->head = new_element;}else{if (element->next == NULL){list->tail = new_element;}new_element->next = element->next;element->next = new_element;}list->size++;return 0;
}//删除element后的一个元素
int list_rem_next(List *list, ListElmt *element, void **data)
{ListElmt *old_element;if (list->size == 0)return -1;if (element == NULL){*data = list->head->data;old_element = list->head->next;list->head = list->head->next;if (list->size == 1)list->tail = NULL;}else{if (element->next == NULL)return-1;*data = element->next->data;old_element = element->next;element->next = element->next->next;if (element->next == NULL){list->tail = element;}}free(old_element);list->size--;return 0;
}

双链表

双向链表,如同其名字所暗示的那样,链表元秦之间由两个指针链接。双向链表中的每元素都由3部分组成:除了数据成员和nexr指针外,每个元素还包含一个指向共前驱元素的指针,称为prev指针。双向链表的组成是这样的:将一些元素链接在一起使得每个元素的 next指针都指向其后继的元素,而每个元素的rev指针都指向其前驱元素。为了标识链表的头和尾,将第一个元素的prev指针和最后一个元素的nexr指针设置为NULL。要反向遍历整个双向链表,使用prev指针以从尾到头的顺序连续访问各个元素。因此,为每个元素増加了一个指针的代价,换来的是双向链表比单锥表提供了更为灵活的访问方式。当我们知道某个元素存储在链表中的某处时,我们可以明智地途择按照何种方式访问到它,这会非常有帮助。例如,双向链表的一种灵活性在于它提供了一种比单链表更直观的方式以移除一个元素

具体代码实现

#include<stdlib.h>
#include<string.h>
typedef struct DListElmt    //节点属性
{void *data;struct DListElmt *prev;struct DListElmt *next;
}DListElmt;typedef struct DList
{int size;int(*match)(const void *key1, const void *key2);void(*destroy)(void *data);DListElmt *head;DListElmt *tail;
}DList;#define dlist_is_head(element) ((element)->perv == NULL ? 1:0)  //是否是头
#define dlist_is_tail(element) ((element)->next == NULL ? 1:0)  //是否是尾//创建链表
void dlist_init(DList *list, void(*destroy)(void *data))
{list->size = 0;list->destroy = destroy;list->head = NULL;list->tail = NULL;return;
}//删除节点
int dlist_remove(DList *list, DListElmt *element, void **data)
{if (element == NULL || list->size == 0)return 1;*data = element->data;if (element == list->head)       //如果是头节点,则判空。{if (list->head == NULL)    //为空则是最后一个节点,清空连接list->tail = NULL;elseelement->next->prev = NULL;  //非空,则摘除节点,准备删除}else   //如果不是头结点,摘除。删除{element->prev->next = element->next; //删除节点的前一个指向删除节点的后一个if (element->next == NULL)    //判断是否为最后一个节点list->tail = element->prev;elseelement->next->prev = element->prev; //删除节点的后一个指向删除节点的前一个}free(element);list->size--;return 0;
}//删除链表
void dlist_destroy(DList *list)
{void *data;while (list->size > 0){if (dlist_remove(list, list->tail, (void **)&data) == 0&& list->destroy != NULL)//如果节点删除成功,则删除节点对应存储的数据list->destroy(data);}
}//尾插法
int dlist_ins_next(DList *list, DListElmt *element, const void *data)
{DListElmt *new_element;if (element == NULL && list->size != 0)return -1;if ((new_element = (DListElmt*)malloc(sizeof(DListElmt))) == NULL)return -1;new_element->data = (void *)data;if (list->size == 0)    //如果为链表头{list->head = new_element;list->head->prev = NULL;list->head->next = NULL;list->tail = new_element;}else{new_element->next = element->next;new_element->prev = element;if (element->next == NULL)list->tail = new_element;elseelement->next->prev = new_element;element->next = new_element;}list->size++;return 0;
}//头插法
int dlist_ins_prev(DList *list, DListElmt *element, const void *data)
{DListElmt *new_element;if (element == NULL  && list->size != 0)return -1;if ((new_element = (DListElmt*)malloc(sizeof(DListElmt))) == NULL)return -1;new_element->data = (void *)data;if (list->size == 0){list->head = new_element;list->head->prev = NULL;list->head->next = NULL;list->tail = new_element;}else{new_element->next = element;new_element->prev = element->prev;if (element->prev == NULL)list->head = new_element;elseelement->prev->next = new_element;element->prev = new_element;}list->size++;return 0;
}

算法精解(一):C语言描述(链表)相关推荐

  1. 《 算法精解:c语言描述》chm 电子书下载

    本电子书包括基本算法分析原理,基本数据结构.抽象数据结构.递归和树等数据结构知识,选择排序.插入排序.冒泡排序.希尔排序.快速排序方法.归并和归并排序方法.优先队列与堆排序方法.基数排序方法以及特殊用 ...

  2. 资料 | O‘Reilly精品图书系列:算法精解 C 语言描述 (简体中文)

    下载地址:资料 | O'Reilly精品图书系列:算法精解 C 语言描述 (简体中文) 内容简介 · · · · · · 本书是数据结构和算法领域的经典之作,十余年来,畅销不衰! 全书共分为三部分:第 ...

  3. JVM内存管理------GC算法精解(五分钟让你彻底明白标记/清除算法)

    转载自  JVM内存管理------GC算法精解(五分钟让你彻底明白标记/清除算法) 相信不少猿友看到标题就认为LZ是标题党了,不过既然您已经被LZ忽悠进来了,那就好好的享受一顿算法大餐吧.不过LZ丑 ...

  4. JVM内存管理------GC算法精解(复制算法与标记/整理算法)

    转载自  JVM内存管理------GC算法精解(复制算法与标记/整理算法) 本次LZ和各位分享GC最后两种算法,复制算法以及标记/整理算法.上一章在讲解标记/清除算法时已经提到过,这两种算法都是在此 ...

  5. JVM内存管理------GC算法精解(五分钟教你终极算法---分代搜集算法)

    转载自   JVM内存管理------GC算法精解(五分钟教你终极算法---分代搜集算法) 引言 何为终极算法? 其实就是现在的JVM采用的算法,并非真正的终极.说不定若干年以后,还会有新的终极算法, ...

  6. 算法可以用不同的语言描述如果用c语言,【判断题】算法可以用不同的语言描述,如果用C 语言或PASCAL语言等高级语言来描述,则算法实际上就是程序了。...

    [判断题]算法可以用不同的语言描述,如果用C 语言或PASCAL语言等高级语言来描述,则算法实际上就是程序了. 更多相关问题 [判断题] 一个优秀的新闻编辑的能力结构应包括分析问题的能力.引导舆论的能 ...

  7. 算法精解_C语言 链表_单链表(接口定义+类型实现)

    链表可以说是一种最为基础的数据结构.链表由一组元素以一种特定的顺序组合或链接而成,在维护数据的集合时很有用.这一点同我们常用的数组很相似.然而,链表在很多情况下比数组更有优势.特别是在执行插入和删除操 ...

  8. 算法精解 c语言描述 豆瓣,斯坦福大学教授亲授,这本美亚4.7星的算法书,新手程序员都看得懂!...

    原标题:斯坦福大学教授亲授,这本美亚4.7星的算法书,新手程序员都看得懂! "算法会扩展并提高大家的编程技巧,而学习基本的算法设计范式,可以和许多不同领域的不同问题密切相关,还能作为预测算法 ...

  9. 算法精解(三):C语言描述(链表常见问题)

    1.如何判断两个单链表是否相交,如果相交,找出交点(两个链表都不存在环) 如果两个单链表相交,那应该呈"Y"字形,则交点之后的节点是相同的. 所以判断是否相交,只需看两个链表的最后 ...

  10. 算法精解一(C语言版)

    最近无事  抽出点时间来整理一下算法  希望对自己有进一步的帮助和对学习算法的同行有一些帮助吧! 讲到算法  这个词是很重一个解决问题的途径 无论在什么行业 算法都是很重要的. 不管你是否承认,无论哪 ...

最新文章

  1. npm install 报错 npm ERR! code Z_BUF_ERROR 问题解决
  2. 实际程序调用IndexWriter* writer = NULL
  3. 总结一哈JDK和Tomcat的环境变量配置
  4. MySQL高级 - SQL优化 - group by 优化
  5. 如何使用SAP CRM增强工具AET创建Table表格类型的增强
  6. tensorflow 语义slam_【论文阅读28】DynaSLAM
  7. java高级编程期末考试题_java高级编程考题
  8. gx works2 存储器空间或桌面堆栈不足_静态体验奇瑞艾瑞泽GX冠军版,细节做工很精湛...
  9. Dubbo介绍前篇------单一应用框架、垂直应用框架、分布式应用框架、流动计算框架,及RPC的简介
  10. c语言数组题库答案,C语言数组百道练习题含答案.pdf
  11. webserver/CGI
  12. 基于JSP的网上订餐管理系统
  13. miniGUI-4.0.2 交叉编译
  14. ubuntu安装nvidia和cuda重启后,鼠标键盘失灵
  15. iconfont 新加图标( 在原有项目的图标库中加入新的图标)
  16. 本地化翻译软件测试,本地化测试 - Mr.南柯 - 51Testing软件测试网 51Testing软件测试网-软件测试人的精神家园...
  17. Mybatis框架创建逆向工程步骤
  18. dlib人脸对齐(python)
  19. BZOJ3811: 玛里苟斯
  20. 史上最全的python的web开发和网络编程【附属详细解释+案例】

热门文章

  1. jdk7 linux 32位 安装包 微云网盘下载
  2. vba常用函数详细介绍及示例
  3. 2.2 BubbleSort
  4. FFmpeg解码H264视频流局部花屏解决方法
  5. 手写字体生成器,这种软件居然被大佬做出来了!
  6. vb学生管理系统服务器编程,利用VB进行服务器编程实例汇总.doc
  7. .net反编译工具Reflector下载
  8. Python实战教程 | 轻松批量识别数百个快递单号
  9. 网管员的任务与职责漫谈
  10. Oracle10G各版本下载