`

《实用算法》学习笔记_2

 
阅读更多

C语言中数组必须在编写程序时定义,在定义一个数组时,还必须定义它的大小。

假如需要编写一个程序,从输入文件中读取城市的名称及气温信息。最后按照温度和城市进行排序,并确定中间气温。

对于这个问题,使用数组并不是一个好的选择。因为你不知道应该创建多大的数组才合适。或许可以声明一个认为足够大的数组,但是这会浪费内存空间,并且还有输入文件超出预期的风险。

一种方案是读两遍输入文件,第一遍确定大小,第二遍再进行数据处理。但是因为磁盘I/O是非常慢的(它几乎是总是程序中最慢的),这样效率非常低,并不可取。

一个好的方法是利用链表,它按接收到的数据来存储它们。


下面是一个利用链表,读入输入文件,并按照气温城市进行排序的算法:


/*--- citytemp.c--------------------------- Listing 2-1 ---------
 *  Reads a text file of cities and temperatures in the
 *  following format:   TempCity
 *      where Temp is a number of three digits or
 *      a sign and two digits; City is a string of length < 124
 *  Examples:     -10Duluth
 *                096Phoenix
 *  The records are read into a singly linked list by order
 *  of temperature and city; duplicates are discarded. At EOF,
 *  the whole list is printed with an indication of the median
 *  temperature. And then, the list is progressively shortened
 *  and reprinted showing the median.
 *              Usage: citytemp filename.ext
 *-------------------------------------------------------------*/

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

/*--- data definitions ---*/

struct Node {           /* a node in our linked list */
    char  *City;
    int    Temp;
    struct Node *Next;
};

typedef struct Node * Link; /* Links are pointers to nodes */

Link Head;              /* head of our linked list */
int  NodeCount;         /* how many nodes in the list */

/*--- functions declarations for linked lists ---*/

int  AddNodeAscend ( Link );        /* add a node           */
void CreateList ( void );           /* initialize list      */
int  DeleteNode ( Link );           /* delete a node        */
int  DuplicateNode ( Link, Link );  /* handle duplicate inserts */
void FreeNode ( Link );             /* free a node's memory */
void ShowNodes ( void );            /* show list of nodes   */
int  NodeCmp ( Link, Link );        /* compare two nodes    */

/*--- function definitions ---*/

int AddNodeAscend ( Link to_add )
{
    Link   pn,   /* 指向将被插入的节点*/
           prev, /* 指向当前被检查节点的前一节点 */
           curr; /* 指向当前被检查的节点 */
    struct Node dummy;
    int    i;

    /* 拷贝插入节点 */
    pn = ( Link ) malloc ( sizeof ( struct Node ));
    if ( pn == NULL )
        return 0;
    memcpy ( pn, to_add, sizeof ( struct Node ));

    /* 建立头节点,使逻辑更简单 */
    dummy.Next = Head;
    prev = &dummy;
    curr = Head;

    /* 插入pn指向的节点 */
    for ( ;; prev = curr, curr = curr->Next )
    {
        if ( curr == NULL )
            break; /* 到达链表尾 */

        i = NodeCmp ( pn, curr );//比较pn节点与curr节点
        if ( i <= 0 )
             break; /* pn节点值小于当前节点curr */
    }

    if ( curr && i == 0 ) /* 判断是否重复节点 */
        if ( DuplicateNode ( curr, pn ) == 0 )
            return ( 1 ); /* 释放重复节点的空间 */

	//插入
    prev->Next = pn;
    pn->Next = curr;

    Head = dummy.Next;//重新定位head,因为若是插入成第一个节点,
	                                 //不重新定位,head就不是指向第一个节点了
	NodeCount+=1;//节点数加1
    return ( 1 );
}

/*--------------------------------------------------------------
 * Handle the duplicate node. In this program,
 * we just delete the duplicate.
 *-------------------------------------------------------------*/
int DuplicateNode ( Link inlist, Link duplicate )//处理重复节点
{
    FreeNode ( duplicate );//调用FreeNode,释放重复节点的空间
    return ( 0 );
}

int DeleteNode ( Link to_delete )
{
    Link curr,  /* 指向当前节点 */
         prev;  /* 指向当前节点的前一节点 */
    int  i;

    /*---判断是不是空表 ---*/
    if ( Head == NULL )
        return ( 0 );

    /*--- 非空,寻找要删除的节点 ---*/
    for ( prev = NULL, curr = Head;
        curr != NULL && ( i = NodeCmp ( to_delete, curr )) > 0;
        prev = curr, curr = curr->Next )
        /* loop around */ ;

    /*--- 找到匹配条件的,删除之---*/
    if ( curr != NULL && i == 0 )//compare之后,若是相同的节点,返回值是0
    {
        if ( prev )
            prev->Next = curr->Next;
        else              /* deleting Head */
            Head = curr->Next;//第一个节点就是匹配待删除的节点

        FreeNode ( curr );//释放内存
        NodeCount -= 1;//节点数量减1
        return ( 1 );
    }

    return ( 0 );
}


//按温度、城市的规则比较两个节点
int NodeCmp ( Link a, Link b )
{ 
	 /* 如果温度不同,按温度排序 */
    if ( a->Temp != b->Temp )
        return ( a->Temp - b->Temp );
    /*温度相同,按城市排序 */
    return strcmp ( a->City, b->City );
}

//创建空链表(并没有头结点)
void CreateList ( void )
{
    Head = NULL;
    NodeCount = 0;
}

//释放节点内存
void FreeNode ( Link n )
{
    free ( n->City );
    free ( n );
}

//展示节点群
void ShowNodes( void )
{
    Link pn;
    int count, median;	
	median = NodeCount/2+1;
    //遍历链表城市与温度,并指出中点     
    if ( NodeCount ) /* 当且仅当存在节点才展示 */
    {      
        count = 0;     /* 计算打印的节点 */
        for ( pn = Head; pn; pn = pn->Next )
        {
            printf ( "%-20s: %3d", pn->City, pn->Temp );
            count += 1;
            if ( count == median )
                printf ( " --Median--" );
            printf ( "\n" );
        }
    }
    else
        printf ( "Empty list\n" );
}

/*--- main line ---*/
int main ( int argc, char *argv[] )
{
    FILE *fin;        /* file we'll be reading from */
    char buffer[128]; /* where we'll read the file into */

    struct Node n;    /* the node we add each time */

    if ( argc != 2 )
    {
        fprintf ( stderr, "Usage: citytemp filename.ext\n" );
        exit ( EXIT_FAILURE );
    }

    fin = fopen ( argv[1], "rt" );
    if ( fin == NULL )
    {
        fprintf ( stderr, "Cannot open/find %s\n", argv[2] );
        exit ( EXIT_FAILURE );
    }

    /* 创建并初始化链表 */
    CreateList();

    /*--- main loop ---*/
    while ( ! feof ( fin ))//循环直到文件流末EOF
    {
       
        if ( fgets ( buffer, 127, fin ) == NULL )//从文件指针fin中读取127-1个字符,存到以buff为起始地址的空间里,直到读完一行,如果成功则返回s的指针,否则返回NULL。
            break;

        /* 置行末字符为结束符 */
        buffer [ strlen ( buffer ) - 1 ] = '\0';

        /* 复制从buff+3开始的字符串 */
        n.City = strdup ( buffer + 3 );

        /* 置行上第4个字符为结束符 */
        buffer[3] = '\0';
        n.Temp = atoi ( buffer );//把行上前3个数字字符转换成整型数

        /* 设置好n节点后,插入链表 */
        if ( AddNodeAscend ( &n ) == 0 )
        {
            fprintf ( stderr, "Error adding node. Aborting\n" );
            exit ( EXIT_FAILURE );
        }
    }

    ShowNodes();

    /* Now, delete something */
    printf( "\n" );
    DeleteNode ( Head );
    ShowNodes();

	//从第一个节点开始,依次删除一个节点并展示节点群
    while (Head && Head->Next)
    {
        printf ( "\n" );
        DeleteNode ( Head->Next );
        ShowNodes();
    }

    printf ( "\n" );
    DeleteNode ( Head );
    ShowNodes();

    fclose ( fin );//关闭流
    return ( EXIT_SUCCESS );
}



涉及的一些函数:


 

void *memcpy(void *dest, const void *src, int n);

从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中

函数返回一个指向dest的指针。



char *fgets(char *s, int n, FILE *stream);

参数:

  *s: 字符型指针,指向将存储到的数据地址。

  n: 整型数据,将从流中读取 n - 1 个字符。

  *stream: 指针数据,欲读取的流。

功能:

  从文件指针stream中读取n-1个字符,存到以s为起始地址的空间里,直到读完一行,如果成功则返回s的指针,否则返回NULL。




int atoi(const char *nptr);

功 能: 把字符串转换成整型数.

名字来源:array to integer 的缩写.

函数说明: 参数nptr字符串,如果第一个非空格字符不存在或者不是数字也不是正负号则返回零,否则开始做类型转换,之后检测到非数字(包括结束符 \0) 字符时停止转换,返回整型数。



extern char *strdup(char *s);

用法:char *strdup(char *s);

功能:复制字符串s

说明:strdup()在内部调用了malloc()为变量分配内存,当程序结束后,必须用free()释放相应的内存空间,否则会造成内存泄漏



extern int strcmp(const char *s1,const char * s2);

  用法:#include <string.h>

  功能:比较字符串s1和s2。

  一般形式:strcmp(字符串1,字符串2)

  说明:

  当s1<s2时,返回值<0

  当s1=s2时,返回值=0

  当s1>s2时,返回值>0

  即:两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇'\0'为止。如:


 



算法实际运行截图:

 








 

分享到:
评论

相关推荐

    算法笔记3_算法笔记_浙大_

    总的来说,《算法笔记3》是一本系统而全面的算法学习资料,它不仅适合浙江大学的学生,也适用于所有希望提升算法能力和C/C++编程水平的读者。通过深入阅读和实践,读者将能够掌握扎实的算法基础,提高编程能力和解决...

    算法笔记1_pat参考书_PAT算法笔记_算法笔记_浙大_

    《算法笔记1.pat参考书.PAT算法笔记.算法笔记.浙大》是一本专为浙江大学计算机科学与技术专业学生及对PAT(Programming Ability Test)考试感兴趣的读者编写的教材。本书重点在于C++和C语言的编程技巧和算法实现,...

    算法笔记4_pat参考书_算法笔记_

    算法笔记》是一本全面且实用的教材,无论你是准备浙大机试还是备考PAT,都能从中受益匪浅。通过阅读和实践书中的内容,你将能够构建扎实的算法基础,提升编程解决问题的能力,为未来的学习和职业生涯打下坚实的基础...

    cpp-算法学习笔记

    【cpp-算法学习笔记】是一份专注于C++编程语言的算法学习资源,旨在帮助开发者深入理解和掌握各种基础及高级算法。这份笔记包含了丰富的实例、解释和练习,是C/C++开发人员提升算法技能的理想教材。在C++这个强大的...

    C语言高级编程及实例剖析_算法笔记_接触问题_

    书中的“算法笔记”部分涵盖了排序、搜索、图论、动态规划等多种经典算法。这些算法是计算机科学的基础,也是解决各种复杂问题的工具。例如,冒泡排序和快速排序是两种常见的排序算法,它们分别通过不断交换元素和...

    Xilinx_FPGA_FFT_应用笔记.rar_FFT笔记_FPGA FFT_Xilinx fft_fft_算法笔记

    首先,笔记会介绍FFT的基本原理,包括离散傅里叶变换(DFT)和它的逆变换IDFT,以及FFT如何通过分治策略将复杂的DFT计算复杂度从O(N^2)降低到O(N log N)。读者会了解到蝶形运算(Butterfly Operation)这一核心概念...

    算法学习笔记

    通过上述内容可以看出,动态规划和字符串处理是算法学习中非常重要且实用的部分。动态规划能够有效地解决具有重叠子问题的最优化问题,而字符串处理则涵盖了从简单到复杂的多种应用场景。无论是对于学术研究还是实际...

    c语言 实用基础 算法 笔记 指针

    本笔记集包含了C语言的基础知识和实用算法,旨在帮助学习者深入理解和掌握C语言的核心概念。 一、C语言基础知识 1. 变量与数据类型:C语言提供了多种数据类型,如整型(int)、字符型(char)、浮点型(float、...

    算法笔记.胡凡(完整版)

    胡凡(完整版)》是胡凡主编的一部全面且深入的算法学习资料,涵盖了计算机科学中算法的基础理论与实践应用。这本书以其详尽的解释、丰富的实例和实用的编程练习,深受广大程序员和计算机科学爱好者的喜爱。在本篇中,...

    数据结构和算法学习笔记

    ### 数据结构和算法学习笔记之复杂性分析及补偿分析法详解 #### 一、引言 数据结构和算法是计算机科学中的核心概念,对于软件开发人员来说至关重要。它们不仅能够帮助我们有效地解决问题,还能优化程序的性能。在...

    胡凡 曾磊 算法笔记

    书籍的第2章便是一个C语言的入门教程,内容非常易懂,并且十分实用,阅读完这章就可以对本书需要的C语言基础有一个较好的掌握。 本书已经覆盖了大部分基础经典算法,不仅可以作为考研机试和PAT的学习教材,对其他的...

    KMP 算法学习笔记.pdf

    ### KMP 算法详解 #### 一、KMP 算法简介 KMP 算法,全称为 Knuth-Morris-Pratt ...通过对 `next` 数组的巧妙构造,KMP 算法能够在不增加额外时间复杂度的情况下快速完成字符串匹配任务,是一种非常实用且高效的算法。

    算法笔记+上级训练实战.zip

    《算法笔记+上级训练实战.zip》是一份包含算法学习与实践资源的压缩文件,主要包含两部分:《算法笔记》和《算法笔记-上机训练实战指南》。这两个PDF文档旨在帮助读者深入理解和掌握算法这一核心的计算机科学概念,...

    labuladong的算法秘籍+刷题笔记V2.0

    总而言之,"labuladong的算法秘籍+刷题笔记V2.0"是一套全面、深入且实用的学习资料,无论你是初学者还是有一定经验的开发者,都能从中获益匪浅。通过系统地阅读和实践书中的内容,不仅可以提升编程技能,还能为面试...

    算法笔记上机训练指南

    《算法笔记上机训练指南》是一本专注于算法学习的习题集,它旨在帮助读者通过专题性质的上机训练来加深对算法概念和实现的理解。作为一本《算法笔记》的配套材料,这本书的出发点是希望读者通过有计划地按照不同算法...

    吴恩达机器学习笔记-人工智能机器学习算法入门笔记

    在实际应用中,需要考虑模型选择、交叉验证、偏差/方差分析、特征工程以及学习曲线等重要因素,以确保模型的泛化能力和实用性。同时,误差分析、异常检测和数据可视化也是提升模型性能的关键步骤。 总之,机器学习...

    算法笔记胡凡pdf

    本书还有配套的《算法笔记上机训练实战指南》本书的作者是同样经历过考研机试和各类算法考试的专家型学长,知晓这类考试中的痛点,以及考生在学习算法时容易产生困惑的地方,因此可以把本书看作是学长为你奉献的满满...

    算法笔记.pdf

    在理解算法和程序的同时,重要的是要掌握如何对算法进行正确的时间复杂度分析,因为这直接关系到算法的效率和实用性。通过合理选择算法设计模式和优化算法的实现,可以在实际应用中大幅提升系统性能。学习算法的过程...

    算法笔记.胡凡(详细书签)

    书籍的第2章便是一个C语言的入门教程,内容非常易懂,并且十分实用,阅读完这章就可以对本书需要的C语言基础有一个较好的掌握。 本书已经覆盖了大部分基础经典算法,不仅可以作为考研机试和PAT的学习教材,对其他的...

    PAT CCF 算法笔记 PDF

    《PAT CCF 算法笔记》是一本深入浅出的算法学习资料,由知名教师胡大大精心编纂。这本笔记以其清晰易懂的讲解风格,成为了许多学习算法的朋友们的首选。它不仅适用于初学者,对于有一定基础的程序员来说,也是提升...

Global site tag (gtag.js) - Google Analytics