数据结构(三)双向链表

一、什么是 make 工具?

make 是一个自动化构建工具,主要用于管理 C/C++ 项目的编译和链接过程。它通过读取 Makefile 文件中定义的规则,自动判断哪些文件被修改,并仅重新编译这些部分,从而大幅提高构建效率。


二、什么是 Makefile?

Makefilemake 工具的配置文件,它以纯文本形式存在,主要用于描述:

  • 构建目标(如:最终生成的可执行文件)

  • 依赖关系(如:源代码、头文件)

  • 构建命令(如:gcc 编译命令)

通过 Makefile,我们可以实现对大型项目的自动化编译管理。


三、Makefile 的基本语法

1. 基本格式

目标文件: 依赖文件列表 命令(以Tab键开头)

注意:命令必须以 Tab 缩进,否则 make 会报错。

示例:

a.out: main.c fun.c

gcc main.c fun.c -o a.out -I$(INC) -L$(LIB)

  • 目标文件:a.out(最终生成的可执行文件)

  • 依赖文件:main.c、fun.c

  • 命令:gcc 编译命令,带有头文件和库路径参数


四、常用编译参数说明

  • -I$(INC):指定头文件目录(如 include/

  • -L$(LIB):指定库文件目录(如 lib/

  • -o:指定输出文件名称


五、Makefile 中的变量使用

1. 自定义变量

CC = gcc

TARGET = app

SRC = main.c fun.c

INC = ./include

LIB = ./lib

引用变量方式:$(变量名

$(TARGET): $(SRC)

$(CC) $(SRC) -o $(TARGET) -I$(INC) -L$(LIB)

2. 系统自动变量

  • $@:表示当前规则的目标文件

  • $^:所有依赖文件(去重)

  • $<:第一个依赖文件

示例:

app: main.c fun.c tool.c gcc $^ -o $@

等价于:

gcc main.c fun.c tool.c -o app


六、make 的时间戳机制

make 会对比文件的时间戳来判断是否需要重新编译:

  • 若依赖文件比目标文件更新 → 执行构建命令

  • 否则跳过(显示 make: 'xxx' is up to date.

这种机制确保了编译效率,尤其适合大型项目。


七、GCC 编译的四个阶段

  1. 预处理(Preprocessing)

    处理 #include#define 等预处理指令,生成 .i 文件:

    gcc -E main.c -o main.i

  2. 编译(Compilation)

    .i 转为汇编 .s 文件:

    gcc -S main.i -o main.s

  3. 汇编(Assembly)

    .s 文件生成 .o 目标文件:

    gcc -c main.s -o main.o

  4. 链接(Linking)

    将多个 .o 文件和库链接为可执行程序:

    gcc main.o fun.o -o app


八、Makefile 示例(推荐写法)

cs 复制代码
# 定义变量  
CC = gcc  
CFLAGS = -I./include -Wall  # 编译选项:指定头文件目录 + 显示警告  
LDFLAGS = -L./lib -lm       # 链接选项:指定库目录 + 链接数学库  
TARGET = app  
SRCS = main.c fun.c  
OBJS = $(SRCS:.c=.o)        # 将 .c 文件转换为 .o 文件(如 main.c → main.o)  
 
# 默认目标(第一个目标为默认)  
all: $(TARGET)  
 
# 生成可执行文件  
$(TARGET): $(OBJS)  
    $(CC) $(OBJS) -o $@ $(LDFLAGS)  
 
# 生成目标文件(.o)  
%.o: %.c                    # 模式规则:所有 .o 依赖对应的 .c  
    $(CC) -c $< -o $@ $(CFLAGS)  
 
# 清理编译产物  
clean:  
    rm -f $(OBJS) $(TARGET)  

使用方法

  • 编译项目:make(默认执行 all 目标)
  • 清理文件:make clean
  • 重新编译:make clean && make

九、Makefile 使用方法

操作 命令
编译项目 make(默认执行 all)
清理项目 make clean
重新编译 make clean && make

十、双线链表基础语法

头文件

cs 复制代码
#ifndef _SIZEOF_DOUBLE_
#define _SIZEOF_DOUBLE_


typedef struct stu
{
    int id;
    char name[32];
    int score;
}Data_type;

typedef struct dounode
{
    Data_type data;
    struct dounode *ppre;
    struct dounode *pnext;
}DNode;

typedef struct doulink
{
    DNode *phead;
    int clen;
}Dlink;

extern Dlink *creatDoulink();
extern int IsEmptyDouLink(Dlink *pdlink);
extern int insertHeadDouLink(Dlink *pdlink, Data_type data);
extern void printDouLink(Dlink *pdlink, int dir);
extern int insertTailDouLink(Dlink *pdlink, Data_type data);
extern int deleteHeadDouLink(Dlink *pdlink);
extern int deleteTailDouLink(Dlink *pdlink);
extern int DestroyDouLink(Dlink *pdlink);

extern DNode *findNameDouLink(Dlink *pdlink, char *s);

extern int modifyScoreByName(Dlink *pdlink, char *s, int Score);
extern int deleteNodeByName(Dlink *pdlink, char *s);
#endif

定义函数

cs 复制代码
#include "doulink.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

Dlink *creatDoulink()
{
    Dlink *pdlink = malloc(sizeof(Dlink));
    if (NULL == pdlink)
    {
        printf("malloc error\n");
        return NULL;
    }
    pdlink->phead = NULL;
    pdlink->clen = 0;

    return pdlink;
}

int IsEmptyDouLink(Dlink *pdlink)
{
    return NULL == pdlink->phead;
}

int insertHeadDouLink(Dlink *pdlink, Data_type data)
{
    DNode *pnode = malloc(sizeof(DNode));
    if(NULL == pnode)
    {
        printf("malloc error\n");
        return -1;
    }
    pnode->data = data;
    pnode->pnext = NULL;
    pnode->ppre = NULL;

    if(IsEmptyDouLink(pdlink))
    {
        pdlink->phead = pnode;
    }
    else
    {
        pnode->pnext = pdlink->phead;
        pdlink->phead->ppre = pnode;
        pdlink->phead = pnode; 
    }
    pdlink->clen++;
    return 0;
}

void printDouLink(Dlink *pdlink, int dir)
{
    if(IsEmptyDouLink(pdlink))
    {
        return ;
    }
    DNode *temp = pdlink->phead;
    if(dir)
    {
        while(temp)
        {
            printf("%d %s %d\n", temp->data.id, temp->data.name, temp->data.score);
            temp = temp->pnext;
        }
    }
    else
    {
        temp = pdlink->phead;
        while(temp->pnext)
        {
            temp = temp->pnext;   
        }
        while(temp)
        {
            printf("%d %s %d\n", temp->data.id, temp->data.name, temp->data.score);
            temp = temp->ppre;
        }
    }
    return ;
}

int insertTailDouLink(Dlink *pdlink, Data_type data)
{
    if(IsEmptyDouLink(pdlink))
    {
        insertHeadDouLink(pdlink, data);
        return 1;
    }
    else
    {
        DNode *pnode = malloc(sizeof(DNode));
        if(NULL == pnode)
        {
            printf("malloc error\n");
            return -1;
        }
        pnode->data = data;
        pnode->ppre = NULL;
        pnode->pnext = NULL;

        DNode *temp = pdlink->phead;
        while (temp->pnext)
        {
            temp = temp->pnext;
        }
        pnode->ppre = temp;
        temp->pnext = pnode;
        pdlink->clen++;
        return 1;
    }
}

int deleteHeadDouLink(Dlink *pdlink)
{
    if(IsEmptyDouLink(pdlink))
    {
        return -1;
    }

    if(pdlink->phead->pnext == NULL)
    {
        free(pdlink->phead);
        pdlink->phead = NULL;
        pdlink->clen--;
        return 1;
    }
    else
    {
        DNode *temp = pdlink->phead->pnext;
        temp->ppre = NULL;
        free(pdlink->phead);
        pdlink->phead = temp;
        pdlink->clen--;
        return 1;
    }

}

int deleteTailDouLink(Dlink *pdlink)
{
    if(IsEmptyDouLink(pdlink))
    {
        return -1;
    }
    if(pdlink->phead->pnext == NULL)
    {
        free(pdlink->phead);
        pdlink->phead = NULL;
        pdlink->clen--;
        return 1;
    }
    else
    {
        DNode *temp = pdlink->phead;
        while(temp->pnext)
        {
            temp = temp->pnext;
        }
        temp->ppre->pnext = NULL;
        free(temp);
        pdlink->clen--;
        return 1;
    }
}

int DestroyDouLink(Dlink *pdlink)
{
    DNode *temp = pdlink->phead;
    while(temp)
    {
        pdlink->phead = temp->pnext;
        free(temp);
        temp = pdlink->phead;
    }
    free(pdlink);
    return 1;
}

DNode *findNameDouLink(Dlink *pdlink, char *s)
{
    if(IsEmptyDouLink(pdlink))
    {
        return NULL;
    }
    DNode *temp = pdlink->phead;
    while(temp)
    {
        if(strcmp(temp->data.name, s) == 0)
        {
            return temp;
        }
        temp = temp->pnext;
    }
    return NULL;
}

int modifyScoreByName(Dlink *pdlink, char *s, int Score)
{
    DNode *temp = findNameDouLink(pdlink, s);
    if(temp == NULL)
    {
        return -1;
    }
    temp->data.score = Score;
    return 1;
}

int deleteNodeByName(Dlink *pdlink, char *s)
{
    if(IsEmptyDouLink(pdlink))
    {
        return -1;
    }
    DNode *temp = findNameDouLink(pdlink, s);
    if(temp->ppre == NULL)
    {
        deleteHeadDouLink(pdlink);
        return 1;
    }
    if(temp->pnext == NULL)
    {
        deleteTailDouLink(pdlink);
        return 1;
    }
    temp->pnext->ppre = temp->ppre;
    temp->ppre->pnext = temp->pnext;
    free(temp);
    pdlink->clen--;
    return 1;  
}

主函数

cs 复制代码
#include "doulink.h"
#include<stdio.h>

int main(int argc, char const *argv[])
{
    Data_type stus[5] = 
    {
        {1, "zhangsan", 99},
        {2, "lisi", 100},
        {3, "wangwu", 90},
        {4, "maliu", 56},
        {5, "tianqi", 66},
    };

    Dlink *pdlink = creatDoulink();
    if(NULL == pdlink)
    {
        return -1;
    }

    insertHeadDouLink(pdlink, stus[0]);
    insertHeadDouLink(pdlink, stus[1]);
    insertHeadDouLink(pdlink, stus[2]);
    insertHeadDouLink(pdlink, stus[3]);
 //   insertHeadDouLink(pdlink, stus[4]);

    printDouLink(pdlink, 1);
    // printDouLink(pdlink, 0);

//   deleteHeadDouLink(pdlink);
//   deleteTailDouLink(pdlink);

    printf("----------find----------\n");

//    insertTailDouLink(pdlink, stus[4]);

//    printDouLink(pdlink, 1);

    DNode * temp = findNameDouLink(pdlink, "lisi");
    printf("%d %s %d\n", temp->data.id, temp->data.name, temp->data.score);

        printf("----------modify----------\n");
    modifyScoreByName(pdlink, "wangwu", 999);
    
    printDouLink(pdlink, 1);
    printf("----------deletes design----------\n");
    deleteNodeByName(pdlink, "zhangsan");
    printDouLink(pdlink, 1);

   
    DestroyDouLink(pdlink);

  

    return 0;
}
相关推荐
JIngJaneIL30 分钟前
家常菜点餐|基于java和小程序的家庭大厨家常菜点餐系统设计与实现(源码+数据库+文档)
java·数据库·小程序·vue·论文·毕设·家常菜点餐系统
熊猫片沃子33 分钟前
Mybatis中进行批量修改的方法
java·后端·mybatis
设计师小聂!1 小时前
力扣热题100-------169.多数元素
java·数据结构·算法·leetcode·多数元素
一只叫煤球的猫1 小时前
基于Redisson的高性能延迟队列架构设计与实现
java·redis·后端
WhyWhatHow1 小时前
JEnv:新一代Java环境管理器,让多版本Java管理变得简单高效
java·后端
艾莉丝努力练剑1 小时前
【数据结构与算法】顺序表和链表、栈和队列、二叉树、排序等数据结构的完整代码收录
c语言·数据结构·学习·链表
保加利亚的风1 小时前
【Java】使用FreeMarker来实现Word自定义导出
java·word
SteveCode.1 小时前
SpringBoot 2.x 升 3.x 避坑指南:企业级项目的实战问题与解决方案
java·spring boot
Yang-Never1 小时前
Kotlin -> object声明和object表达式
android·java·开发语言·kotlin·android studio
风萧萧19991 小时前
Java 实现poi方式读取word文件内容
java·开发语言·word