数据结构(2)双向链表

链表

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

顺序表和链表的优缺点:

存储方式:
        顺序表是一段连续的存储单元
        链表是逻辑结构连续物理结构(在内存中的表现形式)不连续
    时间性能,
        查找 顺序表O(1)
             链表  O(n)
        插入和删除
            顺序表 O(n)
            链表   O(1)
            
    空间性能
            顺序表 需要预先分配空间,大小固定
            链表, 不需要预先分配,大小可变,动态分配    
            
    循环链表
        简单的来说,就是将原来单链表中最有一个元素的next指针指向第一个元素或头结点,链表就成了一个环,头尾相连,就成了循环链表。circultlar linker list.
        
        注意非空表,和空表。多数会加入头结点。
        原来结束的条件是
        p->next != NULL ------->>>>> p-next != Head 

双向链表描述:

typedef struct{   //可自定义char name[32];char sex;int age;int score;
}DATATYPE;
typedef struct node {DATATYPE data;struct node *next,*prev;  //数据以及前后节点指针
}DouLinkNode;typedef struct{   //存储头结点以及当前长度,因为链表的大小是可以动态改变的DouLinkNode *head;  //因此不需要一个固定的容量(tlen)(total len)int clen;
}DouLinkList;

功能:

#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;  //用于showdoulinklist是顺序输出还是逆序输出
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

功能实现:

#include "doulink.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>int findbyname(DATATYPE*data,void* arg)   //用于ModifyDouLinkList的回调
{return (0 == strcmp(data->name,(char*)arg));
}int findbyage(DATATYPE*data,void* arg)  //用于ModifyDouLinkList的回调
{return data->age == *(int*)arg;
}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;
}

结构体中的.与->:

结构体中的.与->:
1.A->a表示A是指向结构体的指针
  A.a表示A是结构体
  
2.“->”是指向结构体成员运算符。
  “.”是断点符号,不属于运算符。
  
3.不论是“->”还是“.”,其访问的对象都是结构体变量(不是指针)

typedef struct 
{int a;int b;
}ADD;void swap(ADD add)
{int tmp = add->a;add->a = add->b;add->b = tmp;
}

调用该函数过后,此时主调函数中结构体ADD成员变量a与b的值发生了改变

通过注册回调实现解耦合:

在c语言中,如果模块A中的某个功能在不同应用场景下需要不同的处理方式,
一般采用如下写法:(伪代码)
void AFunc
{
    if(condition1)
    {
        BFunc();
    }
    if(condition1)
    {
        CFunc();
    }
    if(condition1)
    {
        DFunc();
    }
}

可以看出在使用场景变多时间,均需要修改A模块,
显然不满足c语言"对拓展开放,对修改关闭的原则",
因此采用了注册回调函数的方式,A模块提供了回调函数的接口,
根据需要做出对应实现即可

拿链表的查询函数来举例:

使用回调的方式来实现了不同数据的对应方法:

int findbyname(DATATYPE*data,void* arg)   //用于ModifyDouLinkList的回调
{return (0 == strcmp(data->name,(char*)arg));
}int findbyage(DATATYPE*data,void* arg)  //用于ModifyDouLinkList的回调
{return data->age == *(int*)arg;
}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;
}

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

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

相关文章

nginx代理缓存配置-Linux(CentOS)

代理缓存 1. 编写主配置文件2. 编辑虚拟机配置文件3. 重启nginx服务 nginx代理服务配置&#xff0c;基于http协议 开启代理缓存的前提是已经开启了代理服务&#xff0c;请确保已经开启代理服务 1. 编写主配置文件 主配置文件通常在/etc/nginx/nginx.conf&#xff0c;在该文件…

【云原生】ReplicationController控制器详解

ReplicationController 文章目录 ReplicationController说明一、ReplicationControllere介绍二、ReplicationController如何工作三、运行一个ReplicationController四、编写一个ReplicationController清单注意事项4.1、Pod模板4.2、ReplicationController上的标签4.3、Pod选择算…

python机器学习8--自然语言处理(1)

1.基本定义&#xff1a; 语义&#xff1a;就是一句话的重点是什么。 自定词汇&#xff1a;因为语言、文字太多&#xff0c;自定和处理你所关心的重点词汇。 简体转繁体代码 from opencc import OpenCCtext1 "我去过清华大学" openCC OpenCC(s2t) line openCC.…

Typora 【最新1.8.6】版本安装下载教程 (轻量级 Markdown 编辑器),图文步骤详解,免费领取(软件可激活使用)

文章目录 软件介绍软件下载安装步骤激活步骤 软件介绍 Typora 是一款专为 Markdown 爱好者设计的文本编辑器&#xff0c;它结合了简洁的界面设计与强大的 Markdown 渲染能力&#xff0c;为用户提供了一个流畅、高效的写作环境。以下是对 Typora 更详细的介绍&#xff1a; 核心特…

vue使用mavonEditor(流程图、时序图、甘特图实现)

mavonEditor 安装mavonEditor $ npm install mavon-editor --save使用 // 全局注册import Vue from vueimport mavonEditor from mavon-editorimport mavon-editor/dist/css/index.css// useVue.use(mavonEditor)new Vue({el: #main,data() {return { value: }}})//局部使用…

js-vue中多个按钮状态选中类似于复选框与单选框实现

1.vue中多个按钮状态选中类似于复选框 在Vue中处理多个按钮的选中状态切换&#xff0c;通常我们会利用Vue的响应式数据系统来追踪每个按钮的选中状态。 html <div id"app"> <button v-for"button in buttons" :key"button.id" :c…

MATLAB绘制方波、锯齿波、三角波、正弦波和余弦波、

一、引言 MATLAB是一种具有很强的数值计算和数据可视化软件&#xff0c;提供了许多内置函数来简化数学运算和图形的快速生成。在MATLAB中&#xff0c;你可以使用多种方法来快速绘制正弦波、方波和三角波。以下是一些基本的示例&#xff0c;展示了如何使用MATLAB的命令来实现正弦…

数据科学统计面试问题 -40问

前 40 名数据科学统计面试问题 一、介绍 正如 Josh Wills 曾经说过的那样&#xff0c;“数据科学家是一个比任何程序员都更擅长统计、比任何统计学家都更擅长编程的人”。统计学是数据科学中处理数据及其分析的基本工具。它提供了工具和方法&#xff0c;可帮助数据科学家获得…

第五节shell脚本中的运行流程控制(5.2)

b)应答语句中的变量 #!/usr/bin/expect spawn sh ask.sh set timeout 5 set NAME [ lindex $argv 0 ] set AGE [ lindex $argv 1 ] set SUB [ lindex $argv 2 ] set FEEL [ lindex $argv 3 ] expect {"name" { send "$NAME\r";exp_continue }"old&qu…

【React】条件渲染:深入探讨高效开发技巧与最佳实践

文章目录 一、什么是条件渲染&#xff1f;二、条件渲染的实现方式三、条件渲染的最佳实践四、复杂条件渲染的实现 在现代前端开发中&#xff0c;React 已成为开发者构建用户界面的首选框架之一。React 的强大之处在于其组件化和状态管理能力&#xff0c;而条件渲染则是 React 开…

Linux Vim教程(六):文件操作与保存

目录 1. 打开与关闭文件 1.1 打开文件 1.2 关闭文件 1.3 保存文件 2. 创建和删除文件 2.1 创建新文件 2.2 删除文件 3. 文件浏览与导航 3.1 切换文件 3.2 文件列表 4. 文件保存技巧 4.1 强制保存 4.2 保存为新文件 4.3 自动保存 5. 文件操作的高级技巧 5.1 分割…

防火墙限制docker了

今天有个安全方面的需求&#xff0c;演示环境禁止将3306等高危端口暴露到外网。 于是同事开启了防火墙&#xff0c;仅将应用端口暴露。结果导致演示环境无法使用。 由于公司的应用是基于docker部署的。结果他问我为什么同一台机器&#xff0c;应用无法访问mysql。 docker对于…

ELK Stack入门之部署EFK架构

前言&#xff1a; 日志分析对于现代IT系统来说至关重要&#xff0c;它可以帮助组织机构理解和优化其业务和技术基础设施。以下是日志分析的一些重要性方面&#xff1a; 问题诊断与故障排除&#xff1a; 当系统发生故障或出现异常时&#xff0c;通过对相关日志进行分析&#xf…

SQL labs-SQL注入(五,使用sqlmap进行cookie注入)

本文仅作为学习参考使用&#xff0c;本文作者对任何使用本文进行渗透攻击破坏不负任何责任。 引言&#xff1a; Cookie 是一些数据, 存储于你电脑上的文本文件中。当 web 服务器向浏览器发送 web 页面时&#xff0c;在连接关闭后&#xff0c;服务端不会记录用户的信息。Cookie…

第十一章 数据结构

第十一章 数据结构 11.1 数组 数组是元素的顺序集合&#xff0c;通常这些元素具有相同的数据类型 索引表示元素在数组中的顺序号&#xff0c;顺序号从数组开始处计数 数组元素通过索引被独立给出了地址&#xff0c;数组整体上有一个名称&#xff0c;但每个元素利用数组的的…

elasticsearch 解决全模糊匹配最佳实践

事件背景&#xff1a; 某 CRM 系统&#xff0c;定义了如下两个表&#xff1a; 客户表 t_custom 字段名 类型 描述 idlong自增主键phonestring客户手机......... 客户产品关系表 t_custom_product 字段名 类型 描述 idlong自增主键custom_idlong客户idproduct_idlong产品…

【buildroot系统中qt显示屏触摸方向更改】

buildroot系统和qt的显示触摸不一致&#xff0c;qt程序出现显示触摸上下颠倒问题 操作全部在启动qt程序之前设置系统显示配置 操作全部在启动qt程序之前设置系统显示配置 我的设备是上电自启动我的qt程序&#xff0c;所以为了方便我全部在调用我的qt程序位置处修改vi /etc/ini…

vue如何适应多个页面不同的布局

在 Vue.js 中&#xff0c;要适应多个页面不同的布局&#xff0c;你可以采用以下几种方法&#xff1a; 使用动态组件 (Dynamic Components)&#xff1a; 通过使用 Vue 的动态组件&#xff0c;可以在同一个页面中根据路由动态加载不同的布局组件。 <template><component…

笔记本检测工具 | 爱回收笔记本质检系统 v1.9.6

软件简介 爱回收笔记本质检系统是一款专为笔记本电脑硬件检测而设计的软件。它以其快速的检测速度、简便的操作流程和直观的检测结果&#xff0c;为用户提供了一种高效、易懂的硬件检测解决方案。 这款软件不仅适用于对电脑硬件有一定了解的用户&#xff0c;也特别适合对硬件…

SQL进阶:解锁高级特性,深化数据洞察

掌握了SQL的基础知识后&#xff0c;进一步探索其高级特性将帮助您更高效地处理复杂数据&#xff0c;深化数据分析的广度和深度。本文将带您领略SQL的高级功能&#xff0c;包括窗口函数、存储过程、触发器以及高级查询技巧等&#xff0c;让您在数据处理的道路上更进一步。 一、…