3.数据结构之通用编程思想的引入

Tensorflow入门:数据结构和编程思想 Tensorflow入门:数据结构和编程思想引言: 最近tensorflow很火,看到国内都有不少人开始玩起来了,自己最近有些想法想玩玩,于是开始入门搞一下,因为自己只有一个台式电脑,于是就装了个cpu版的tensorflow,安装过程挺顺利,一两句命令搞定,最后遇到过glibc的版本问题,直接升级了Ubuntu版本就好了。 于是,开始入门了。下面是我学习的笔记,水平有限,如有不对,敬请指教。 阅读详情

数据结构之通用编程思想的引入

引言

首先我们以一个简单的例子引入今天所要讨论的问题,交换两个整形变量的方法是我们常见的问题。比如如下的代码:

void swap(int *a, int *b);

void swap(int *a, int *b)
{
    //采用中间变量int temp进行交换
    int temp = *a  ;
    *a       = *b  ;
    *b       = temp;
}

int main(int argc, char **argv)
{
     int a = 10;
     int b = 20;

     printf("before swap:a = %d, b = %d\n", a, b);
     swap(&a, &b);    //交换两个整形变量
     printf("before swap:a = %d, b = %d\n", a, b);
     return 0;
}

上述的代码虽然可以实现交换两个整型变量,但是有着很大的弊端,因为交换的类型只能被限定在了整型变量,如果我们要交换float类型的变量或者或结构体类型。则需要对交换函数进行重复的书写,如下所示:

//swap函数除了类型由int类型转换为了float类型,其他的操作在原理上是没有任何区别的
void swap(float *a, float *b);

void swap(float *a, float *b)
{
    float temp = *a;
    *a = *b;
    *b = temp;
}

这样一个方式就会造成代码的不断重复编写,其实我们想要做的事情非常的直接,就是为了实现两个变量的交换,而不想关心其类型如何。那就需要我们做一个整体的抽象,把数据类型和算法描述分离开,这样的思想和C++的模板编程非常类似,如果采用C++的模板方式实现任意类型的两个变量的交换,具体实现如下:

templete <class T>
void swap(T &a, T &b)
{
    T temp = a;
    a = b;
    b = temp;
}

很遗憾的是,C语言并不支持模板编程(由其语法约束),但是并不妨碍我们对于泛型编程的思考。如果要使用C语言实现泛型编程的话,需要借助void 指针,从c语言的语法角度出发,void 指针类型可以接受其他任意类型的指针。所以我们依然可以吧int ,float 等指针作为参数进行传递,但是在swap函数的声明中使用void 类型,并且因为void 指针并不能清楚的描述出所指向类型的大内存大小,所以我们需要传递第三个参数length去限定void *所要交换的内存的大小(不同的数据类型传入的大小是不同的)。

具体的代码实现如下所示:

void swap(void *a, void *b, int elem_len)
{
    void *temp = malloc(elem_len);
    if(temp == NULL){
        fprintf(stderr, "the memory is full!\n");
        exit(1);
    }
    memcpy(temp, a, elem_len);
    memcpy(a, b, elem_len);
    memcpy(b, temp, elem_len);

    free(temp);
    temp = NULL;
}

这样就可以实现任意类型两个变量的交换了,再以不同类型数组元素的遍历为例,此处引入了foreach函数以及sort函数,查看他们的通用实现方法,完整代码如下图所示:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if 1
typedef unsigned char Boolean;

typedef void (*Pfunc_print)(void *, int );
typedef Boolean (*Comp)(void *, void *);

void sort_array(int *array, int length);
static void swap1(int *a, int *b);
void print_array(int *array, int length);
void swap(void *a, void *b, int elem_len);
void foreach(void *array, int length, Print_func print);
// print = print_int;


void print_int(void *array, int index);

void print_int(void *array, int index)
{
    printf("%d ", *((int *)array + index));
}

void print_float(void *array, int index);

void print_float(void *array, int index)
{
    printf("%f ", *((float *)array + index));
}

void foreach(void *array, int length, Print_func print)
{
    int i = 0; 

    if(array == NULL || length <= 0 || print == NULL){
        return ;
    }

    for(i = 0; i < length; ++i){
        print(array, i);
        //print = print_int
        //print_int(array, i);
    }
    printf("\n");
}

void swap(void *a, void *b, int elem_len)
{
    void *temp = malloc(elem_len);
    if(temp == NULL){
        fprintf(stderr, "the memory is full!\n");
        exit(1);
    }
    memcpy(temp, a, elem_len);
    memcpy(a, b, elem_len);
    memcpy(b, temp, elem_len);

    free(temp);
    temp = NULL;
}

static void swap1(int *a, int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

void print_array(int *array, int length)
{
    int i = 0;

    if(array != NULL && length > 0){
        for(i = 0; i < length; ++i){
            printf("%d ", array[i]);
        }
        printf("\n");
    }
}

void sort_array(int *array, int length)
{
    int i = 0;
    int j = 0;

    if(array == NULL || length <= 0){
        return ;
    }

    for(i = 0; i < length - 1; ++i){
        for(j = i + 1; j < length; ++j){ 
            if(array[i] > array[j]){
                swap(&array[i], &array[j], sizeof(array[i]));
            }
        }
    }
}

Boolean compare_int(void *a, void *b);


//整型类型元素的比较函数
Boolean compare_int(void *a, void *b)
{
    return *(int *)a > *(int *)b;
}

void sort(void *array, int length, int elem_len, Comp compare);
//对任意类型数组的排序
void sort(void *array, int length, int elem_len, Comp compare)
{
    int i = 0;
    int j = 0;

    if(array == NULL || length <= 0 || elem_len <= 0){
        return ;
    }

    for(i = 0; i < length - 1; ++i){
        for(j = i + 1; j < length; ++j){
           // if(array[i] > array[j]){
           //      swap(&array[i], &array[j], elem_len);
           // }
           if(compare(((char *)array + i * elem_len),
                      ((char *)array + j * elem_len))){
               swap((char *)array + i * elem_len,
                    (char *)array + j * elem_len,
                    elem_len);
           }
        }
    }
}

//测试代码
int main(int argc, char **argv)
{
    int array[] = {12, 2, 34, 31, 1, 67, 15 ,89, 6};
    int length = sizeof(array) / sizeof(array[0]);
    float array1[] = {12.3, 1.2, 0.4, 11.3, 111.44, 24.5};
    int length1 = sizeof(array1) / sizeof(array1[0]);


    foreach(array1, length1, print_float);
    foreach(array, length, print_int);
   // print_array(array, length);
   // sort_array(array, length);
    sort(array, length, sizeof(int), compare_int);
    foreach(array, length, print_int);
   // print_array(array, length);

    return 0;
}
#endif

在介绍完泛型编程技巧的基本技术之后,在后续的数据结构的处理上我们都会实现通用数据结构,体现出C语言也能实现C++stl类似的功能。

敬请期待:

下章《数据结构之通用链表的实现》

5.数据结构之通用动态数组 数据结构之通用动态数组引言1.关于数组我们之前做过简单的介绍,数组是一种物理和逻辑都连续的块存储空间,关于数组的定义主要有三个方式://数组定义的三种方式: int array1[] = {12, 23, 34, 45, 56, 67, 78}; //方法1 int array2[100] = {0}; //方法2int *array3 = NULL;array3 = (int *)mall 阅读详情

相关推荐

C语言数据结构新篇章:从零设计一个通用链表 - 结构与思想

本文介绍了链表数据结构的设计与实现,重点讲解了如何通过信息隐藏技术提高代码安全性。主要内容包括:1. 链表节点的设计(数据域和指针域);2. 链表主体结构(虚拟头节点和大小记录);3. 反思动态数组设计暴露内部数据的问题;4. 使用typedef void*实现信息隐藏的技术(Opaque Pointer);5. 链表初始化、获取大小和销毁等基础功能的实现与测试。文章强调了封装性和安全性在数据结构设计中的重要性,为后续实现链表的核心功能奠定了基础。

Web安全工具库 1233

一位十年软件工程师告诉你什么是编程思想

什么是编程思想?答案可能很会复杂,但也可以很简单。一句话来讲就是,用计算机来解决人们实际问题的思维方式,即编程思想。  我们学习编程语言的最终目的,就是希望用计算机来解决我们的实际问题。那么学习计算机该如何入手,也是很多初学者犯难的一个问题,特别是对与非计算机专业的人来说更是如

shupan001的专栏 5万+

Redis通用数据结构:引入新的数据结构

通过HyperLogLog、Bloom Filter以及其他数据结构类型,开发人员可以解决各种不同的问题,并在极小的空间开销下获得高效的性能。如果你希望在Redis中应用这些新数据结构,请确保使用的是最新的Redis版本,并正确加载相应的模块。新的数据结构被称为"Redis HyperStructure",它是一种多功能的数据结构,可以用于解决各种问题。在最新的Redis版本中,引入了一种新的通用数据结构,为开发人员提供更多灵活性和功能性。本文将介绍这个新的数据结构,并提供相应的源代码示例。

DxJavascript的博客 80

数据结构

数据结构基础 什么是链表? ​ 地下党是一些什么样的人物呢? ​ 在影视作品中,我们可能都见到过地下工作者的经典话语: ​ 上级的姓名、住址,我知道,下级的姓名、住址,我也知道。但是这些都是我们党的秘密,不能告诉你们! ​ 地下党借助这种单线联络的方式,灵活隐秘地传递着各种重要信息。 ​ 在计算机科学领域里,有一种数据结构也恰恰具备这样地特征,这种数据结构就是链表。 链表是一种在物理上非连续、非顺序的数据结构,由若干节点所组成。 单项链表的每一个节点又包

weixin_44967898的博客 259

Pintos基础数据结构:通用链表

由于具体应用中仍然需要对存储于‘链表结点’中的数据进行访问,因此,就需要从指向‘链表元素’的指针推算出包含它的那个‘链表结点’的指针。为此,PINTOS 中引入了一个宏 list_entry,其定义和基本思想如图所示:如果已知某个‘链表元素’的指针为 p,并且该‘链表元素’以字段 elem 的形式包含在‘链表结点’结构 list_nodei 中,宏调用list_entry(p,structlist_nodei,elem)经过展开后就是指向包含该‘链表元素’的‘链表结点’的指针。那么这个指针变量怎么定义呢?

Junds0的博客 1686

Python全栈(二)数据结构和算法之1.算法和数据结构引入

算法具有一定的运行时间,枚举法效率很低;算法是独立存在的一种解决问题的方法和思想,有五大特性,算法的效率可以用执行时间衡量,但是受环境和数据本身的影响。T(n) = O(f(n))为大O时间复杂度表示法,表示代码执行时间随数据规模增长的变化趋势;时间复杂度分析有只关心循环执行次数最多的一段代码和加法原则两种方式,分为最优、平均、最坏等情况;常见时间复杂度包括常数、线性、平方、对数等。timeit模块用来测试代码的执行时间,用于对比算法的执行效率。数据存储方式会影响算法和效率,数据结构是算法处理的载体。

CUFEECR的博客 1395

数据结构与算法随笔之------哨兵变量(编程思想与技巧)

1. 哨兵(sentinel ) 哨兵:顾名思义,指站岗、放哨、巡逻、稽查的士兵。 常用来作为比较,  比大小,快排 比相等与否,判等; int i = 0; while ( i &lt; 10 ){     ...     ++i; } 1 2 3 4 5 while 循环中的变量 i 控制着最终的循环次数。这是非常流行的一个表示法,具有这个作用的变量有时也称为哨兵变量(Sentine...

markconca的博客 3163

Unreal 5 MetaHuman插件全流程:从安装到角色动画生成

本文详细介绍了Unreal 5中MetaHuman插件的全流程使用指南,从安装配置到角色动画生成。通过Quixel Bridge下载预设角色,利用面部捕捉技术赋予数字人模型生命力,并提供材质编辑、性能优化等进阶技巧,帮助用户快速创建照片级真实的虚拟角色。

weixin_29009081的博客 829

数据结构课程设计

目录 1. 需求分析: 4 1.1问题描述: 4 1.2问题要求: 4 2. 概要设计 4 2.1抽象数据类型定义 4 2.2设计思路 4 2.2.1模块调用: 4 3详细设计 6 3.1存储结构设计 6 3.1.1顺序查找的基本思想 6 3.1.2二分法查找(折半查找)的基本思想 7 3.1.3斐波那契查找的前提是待查找的查找表必须顺序存...

大虾米 2万+

OpenCV13-图像噪声:椒盐噪声和高斯噪声

考虑到椒盐噪声会在图像中的任何一个位置随机产生,因此对于椒盐噪声的生成,需要使用OpenCV中能够产生随机数的函数。OpenCV中也没有专门为图像添加高斯噪声的函数,对早在图像中添加椒盐噪声的过程,可以根据需求利用能够产生随机数的函数来完成在图像中添加高斯噪声的任务。椒盐噪声又称作脉冲噪声,他会随机改变图像中的像素值,其样子就像是在图像上随机地撒上一些盐粒和黑椒粒,因此被称为椒盐噪声。函数能够产生均匀分布或者高斯分布的随机数,可以利用该函数产生符合高斯分布的随机数,之后在图像中加入这些随机数即可。

SHLYYY 5121

Zotero内存占用与存储优化:从根源解决卡顿与空间不足

文献管理软件在学术工作中扮演着重要角色,其核心原理是通过数据库管理元数据与附件文件,实现文献的快速检索与组织。然而,随着文献库规模增长,软件的资源管理机制可能面临挑战,尤其是内存占用与存储空间优化问题。从技术价值看,高效的附件管理策略不仅能提升软件响应速度,还能确保数据安全与可移植性。在实际应用场景中,研究者常遇到软件卡顿、存储目录膨胀等痛点,这通常与附件存储模式、缓存机制及数据库维护有关。本文聚焦于Zotero这一主流工具,针对其内存占用高、文件无法删除等常见问题,提供了外置存储、链接附件、数据库维护等系

weixin_34209060的博客 446

数据结构概念引入

抽象数据类型(ADT)的含义是指一个数学模型以及定义在此数学模型上的一组操作。即把数据类型和数据类型上的运算捆在一起,进行封装。引入抽象数据类型的目的是把数据类型的表示和数据类型上运算的实现与这些数据类型和运算在程序中的引用隔开,使它们相互独立。最常用的数据运算有五种:●插入●删除●修改●查找●排序。...

m0_51216771的博客 270

告别谷歌翻译失效!手把手教你用Immersive Translate插件实现双语网页阅读(附Chrome/Edge/Firefox保姆级配置)

本文详细介绍了如何使用Immersive Translate插件实现双语网页阅读,解决谷歌翻译失效的问题。通过Chrome、Edge和Firefox的保姆级配置指南,帮助用户轻松安装和使用这款支持双语对照、智能识别网页内容的翻译插件,提升外文资料阅读效率。

weixin_28683689的博客 484

数据结构引入

文章目录基本概念和术语数据数据元素数据项数据对象数据结构逻辑结构和物理结构逻辑结构集合结构 基本概念和术语 数据 数据:是描述客观事物的符号,计算机内可以操作的对象,是能被计算机识别,并输入给计算机处理的符号集合。 这里的数据其实就是符号,这些符号要具有两种前提: 可以输入到计算机内 能被计算机程序处理 数据元素 数据元素:是组成数据的,有一定意义的基本单位,在计算机中通成作为整体处理,也成为记录。 数据项 数据项:一个数据元素由若干个数据项组成。 数据项是数据不可分割的最小单位。 数据对象 数据对象:

奇迹 990

TC397 EB MCAL开发从0开始系列 之 [17.1] ETH配置实战 - ping/发送

TC397 MCAL 从0开始之 ETH ping测试

yy九歌的博客 1505

AD-Copilot 论文解读:把“大模型看图”升级为“对照检验”的工业异常检测助手

本文提出AD-Copilot,一个面向工业异常检测的视觉语言助手,通过视觉上下文比较解决现有方法的不足。针对工业场景中多模态大模型表现不佳的问题,作者指出核心原因在于缺乏工业数据和比较能力不足。为此,论文提出三个关键贡献:构建Chat-AD数据集,设计Comparison Encoder显式建模图像差异,以及采用多阶段训练策略。实验表明,该方法在MMAD基准上达到82.29%准确率,定位任务提升3.35倍,并展现出良好的泛化能力。消融实验验证了比较模块的有效性,表明其成功源于高质量比较数据与显式比较模块的协

blanokvaffy的博客 330

数据结构——引入

数据结构持续更新中……

zzzzzxm__的博客 872

053、坏点校正(DPC)进阶:静态坏点标定与动态坏点检测算法对比

文章摘要: 本文深入探讨了图像传感器坏点校正(DPC)技术,重点对比静态坏点标定与动态坏点检测算法。作者结合真实案例,指出静态标定在高增益场景下的局限性,并详细解析动态检测的核心算法、参数调优及常见误检问题(如边缘/纹理干扰)。提出“静态为主+动态为辅”的混合方案,强调阈值需随增益、亮度和温度自适应调整。文末总结六条工程建议,包括避免固定阈值、优先使用中值替换、定期更新坏点表等,强调DPC是图像质量的基础防线,需结合传感器特性综合优化。

zzfmlxs的博客 262

数据结构与算法的引入

数据结构与算法 什么是数据结构? 广义上讲,数据结构就是一组有结构的数据 什么是算法 算法就是操作数据的方法 数据结构与算法的关系 数据结构与算法是相辅相成的。数据结构是为算法服务的,算要作用在特点的数据结构之上。 数据结构是静态的,它只是组织数据的一种方式。如果不在它的基础上操作、构建算法,孤立存在的数据是没有用的。 算法的引入 import time start_time = time.time() for a in range(1, 1001): for b in ra

WSZFSNFK的博客 238

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

一. Python数据结构与算法(1概念引入_3)

本小节继续讲解Python内置类型性能分析和数据结构引入,以方便更好地理解数据结构与算法。

小小菜鸡 738

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Scala3新特性解析:通用apply方法机制

你是否曾经在Scala开发中遇到过这样的困境:当函数参数超过22个时,编译器无情地抛出错误?或者在使用高阶函数时,因为参数数量限制而不得不重构代码?Scala 3引入的通用apply方法机制彻底解决了这一长期存在的痛点,为函数式编程带来了前所未有的灵活性。 本文将深入解析Scala 3中的通用apply方法机制,通过详细的代码示例、技术原理和实际应用场景,帮助你全面掌握这一重要特性。 ## 函...

gitblog_00540的博客 506

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

1-算法的引入+时间复杂度+数据结构的引入

一、算法的引入 引入:如果a+b+c=1000,且a^2+b^2=c^2,(a,b,c为自然数),如何求出所有a,b,c可能的组合? 此时使用:枚举法【一种思想】 import time start=time.time() for a in range(1001)...

chuiai8582的博客 255

HuaPu在学:Python数据结构与算法【算法引入 & 数据结构引入 】

文章目录前言一、算法引入二、使用步骤1.引入库2.读入数据总结 前言 以下是花圃在学习Python的数据结构与算法的一些要点内容笔记。 一、算法引入 示例1:如果a+b+c=1000,a2+b2=c**2,列举出所有满足两个式子的所有abc组合? 一种思路枚举法: import time start=time.time() for a in range(1001): for b in range(1001): for c in range(1001): i

yililjljl的博客 187

引入-数据结构的基本概念

鉴于网站中海量的数据结构专业讲解,且作为一个菜鸟、还没有太多时间,我会以最功利性的形式创作类似复习笔记的文章。本期主要对数据结构的基本定义进行梳理。一、数据结构是什么?数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。从方式和集合两个概念我们就可以知道,数据结构必定存在对应的逻辑结构形成“方式”,而集合必定需要拥有存储结构,而运行这两块大类自然也需操作定义及实现。

m0_67168376的博客 1261
上一篇: 2.数据结构之链表面试题
下一篇: 4.数据结构之通用链表实现
linux_player_c
博客等级 码龄13年 214粉丝 134原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值