当前位置: 首页 > wzjs >正文

福州网站建设工作室常用的网络营销方式

福州网站建设工作室,常用的网络营销方式,做一个众筹网站多少钱,wordpress 小学生一、双向链表基础 双向链表示意图(指针永远指向内存开始的区域) 二、双向链表核心操作 1. 创建双向链表 c /*** 创建双向链表头节点* return 成功返回链表指针,失败返回NULL*/ struct DouLinkList* CreateDouLinkList() {// 分配链表头结构…

一、双向链表基础

双向链表示意图(指针永远指向内存开始的区域)

二、双向链表核心操作

1. 创建双向链表

c

/*** 创建双向链表头节点* @return 成功返回链表指针,失败返回NULL*/
struct DouLinkList* CreateDouLinkList()
{// 分配链表头结构体内存struct DouLinkList* dl = (struct DouLinkList*)malloc(sizeof(struct DouLinkList));if(NULL == dl){fprintf(stderr, "CreateDouLinkList malloc error\n");return NULL;}// 初始化链表为空状态dl->head = NULL;  // 头指针置空dl->clen = 0;     // 长度计数器归零return dl;
}

2. 头插法插入节点

 图解第一种情况:

 图解第二种情况:

 

c

/*** 在链表头部插入新节点* @param dl 链表指针* @param data 要插入的数据指针* @return 成功返回0,失败返回1*/
int InsertHeadDouLinkList(struct DouLinkList* dl, struct DATATYPE* data)
{// 为新节点分配内存struct DouNode* newnode = (struct DouNode*)malloc(sizeof(struct DouNode));if(NULL == newnode){fprintf(stderr, "InsertHeadDouLinkList malloc failed\n");return 1;}// 拷贝数据到新节点memcpy(&newnode->data, data, sizeof(struct DATATYPE));// 初始化新节点指针newnode->next = NULL;newnode->prev = NULL;// 新节点指向原头节点newnode->next = dl->head;// 如果原链表非空,设置原头节点的前驱指针if(dl->head){dl->head->prev = newnode;}// 更新链表头指针dl->head = newnode;// 链表长度增加dl->clen++;return 0;
}

3. 双向遍历链表

c

/*** 遍历打印链表内容* @param dl 链表指针* @param dir 遍历方向(FORWADR正向/BACKWADR反向)* @return 总是返回0*/
int ShowDouLinkList(struct DouLinkList* dl, DIR dir)
{struct DouNode* tmp = dl->head;if(FORWADR == dir)  // 正向遍历{printf("Forward traversal:\n");while(tmp){// 打印节点数据printf("Name: %s, Sex: %c, Age: %d, Score: %d\n", tmp->data.name, tmp->data.sex, tmp->data.age, tmp->data.score);tmp = tmp->next;  // 移动到下一个节点}}else if(BACKWADR == dir)  // 反向遍历{printf("Backward traversal:\n");// 先移动到链表尾部while(tmp->next){tmp = tmp->next;}// 从尾部向前遍历while(tmp){printf("Name: %s, Sex: %c, Age: %d, Score: %d\n", tmp->data.name, tmp->data.sex, tmp->data.age, tmp->data.score);tmp = tmp->prev;  // 移动到前一个节点}}return 0;
}

判断双链表是否为空
int IsEmptyDouLinkList(struct DouLinkList* dl) 
{
    return 0 == dl->clen; // 若链表长度(clen)为0,返回1(真),否则返回0(假)
}

获取双链表长度
int GetSizeDouLinkList(struct DouLinkList* dl) 
{
    return dl->clen; // 直接返回链表长度(clen)
}

4. 尾插法插入节点

c

/*** 在链表尾部插入新节点* @param dl 链表指针* @param data 要插入的数据指针* @return 成功返回0,失败返回1*/
int InserTailDouLinkList(struct DouLinkList* dl, struct DATATYPE* data)
{// 空链表直接调用头插法if(IsEmptyDouLinkList(dl)){return InsertHeadDouLinkList(dl, data);}// 查找尾节点struct DouNode* tmp = dl->head;while(tmp->next){tmp = tmp->next;}// 创建新节点struct DouNode* newnode = malloc(sizeof(struct DouNode));if(newnode == NULL){fprintf(stderr, "InserTailDouLinkList malloc failed\n");return 1;}// 初始化新节点memcpy(&newnode->data, data, sizeof(struct DATATYPE));newnode->next = NULL;       // 尾节点的next为NULLnewnode->prev = tmp;        // 前驱指向原尾节点// 将新节点链接到链表尾部tmp->next = newnode;// 链表长度增加dl->clen++;return 0;
}

5. 指定位置插入节点

 

c

/*** 在指定位置插入新节点* @param dl 链表指针* @param data 要插入的数据指针* @param pos 插入位置(0-based)* @return 成功返回0,失败返回1*/
int InserPosDouLinkList(struct DouLinkList* dl, struct DATATYPE* data, int pos)
{int len = GetSizeDouLinkList(dl);// 检查位置合法性if(pos < 0 || pos > len){fprintf(stderr, "Invalid position %d\n", pos);return 1;}// 处理头插和尾插特殊情况if(0 == pos){return InsertHeadDouLinkList(dl, data);}else if(pos == len){return InserTailDouLinkList(dl, data);}// 创建新节点struct DouNode* newnode = malloc(sizeof(struct DouNode));if(newnode == NULL){fprintf(stderr, "InserPosDouLinkList malloc failed\n");return 1;}// 初始化新节点数据memcpy(&newnode->data, data, sizeof(struct DATATYPE));newnode->next = NULL;newnode->prev = NULL;// 定位到插入位置的前一个节点struct DouNode* tmp = dl->head;for(int i = 0; i < pos - 1; ++i){tmp = tmp->next;}// 重新链接指针newnode->next = tmp->next;  // 新节点后继指向原位置节点newnode->prev = tmp;        // 新节点前驱指向前驱节点tmp->next->prev = newnode;  // 原位置节点的前驱指向新节点tmp->next = newnode;        // 前驱节点的后继指向新节点// 链表长度增加dl->clen++;return 0;
}

6. 查找节点

c

/*** 按姓名查找节点* @param dl 链表指针* @param name 要查找的姓名* @return 找到返回节点指针,未找到返回NULL*/
struct DouNode* FindDouLinkList(struct DouLinkList* dl, char *name)
{// 空链表直接返回NULLif(IsEmptyDouLinkList(dl)){return NULL;}struct DouNode* tmp = dl->head;// 遍历链表查找匹配节点while(tmp){if(strcmp(tmp->data.name, name) == 0){return tmp;  // 找到匹配节点}tmp = tmp->next;  // 继续检查下一个节点}return NULL;  // 遍历结束未找到
}

7. 修改节点数据

c

/*** 修改指定节点的数据* @param dl 链表指针* @param name 要修改的节点姓名* @param data 新数据指针* @return 成功返回0,失败返回1*/
int ModifyDouLinkList(struct DouLinkList* dl, char *name, struct DATATYPE* data)
{// 查找目标节点struct DouNode* ret = FindDouLinkList(dl, name);if(NULL == ret){fprintf(stderr, "Node %s not found\n", name);return 1;}// 拷贝新数据到目标节点memcpy(&ret->data, data, sizeof(struct DATATYPE));return 0;
}

8. 双向链表逆序

c

/*** 反转双向链表* @param dl 链表指针* @return 成功返回0,失败返回1*/
int RevertDouLinkList(struct DouLinkList* dl)
{int len = GetSizeDouLinkList(dl);// 长度小于2无需反转if(len < 2){return 1;}// 初始化三个工作指针struct DouNode* Prev = NULL;      // 前驱指针struct DouNode* Tmp = dl->head;   // 当前指针struct DouNode* Next = Tmp->next; // 后继指针while(1){// 反转当前节点的指针Tmp->prev = Next;  // 原后继变为前驱Tmp->next = Prev;  // 原前驱变为后继// 移动指针Prev = Tmp;    // 前驱指针前进Tmp = Next;    // 当前指针前进// 检查是否到达链表末尾if(NULL == Tmp){break;}// 更新后继指针Next = Next->next;}// 更新链表头指针dl->head = Prev;return 0;
}

9. 删除指定节点

c

/*** 删除指定节点* @param dl 链表指针* @param name 要删除的节点姓名* @return 成功返回0,失败返回1*/
int DeleteDouLinkList(struct DouLinkList* dl, char* name)
{// 查找目标节点struct DouNode* tmp = FindDouLinkList(dl, name);if(NULL == tmp){fprintf(stderr, "Node %s not found\n", name);return 1;}// 处理头节点情况if(tmp == dl->head){dl->head = dl->head->next;if(dl->head){dl->head->prev = NULL;  // 新头节点的前驱置空}}// 处理尾节点情况else if(NULL == tmp->next){if(tmp->prev){tmp->prev->next = NULL;  // 前驱节点的后继置空}else{dl->head = NULL;  // 链表只有一个节点的情况}}// 处理中间节点情况else{// 更新后继节点的前驱指针if(tmp->next) {tmp->next->prev = tmp->prev;}// 更新前驱节点的后继指针if(tmp->prev) {tmp->prev->next = tmp->next;}}// 释放节点内存free(tmp);// 链表长度减少dl->clen--;return 0;
}

10. 销毁链表

c

/*** 销毁整个链表* @param dl 链表指针* @return 总是返回0*/
int DestroyDouLinkList(struct DouLinkList* dl)
{struct DouNode* tmp = dl->head;// 循环释放所有节点while(tmp){dl->head = dl->head->next;  // 头指针后移free(tmp);                  // 释放当前节点tmp = dl->head;             // 指向新的头节点}// 释放链表头结构free(dl);return 0;
}

三、Makefile工程管理

基础版本

makefile

# 简单Makefile示例
# 目标:依赖
a.out: main.c ./doulink.c# 编译命令(前面必须是tab)gcc main.c doulink.c# 清理目标
clean:rm a.out

推荐版本

makefile

# 定义编译器和编译选项
CC = gcc
CFLAGS = -Wall -g  # 开启所有警告和调试信息# 定义目标可执行文件
TARGET = app# 定义源文件
SRCS = main.c doulink.c# 默认目标规则
$(TARGET): $(SRCS)$(CC) $(CFLAGS) -o $@ $^# 清理规则
clean:rm $(TARGET).PHONY: clean  # 声明clean为伪目标

使用说明

  1. 编译:make (自动执行第一条规则)

  2. 运行:./app (或./a.out如果是基础版本)

  3. 清理:make clean (删除生成的可执行文件)

四、双向链表VS单向链表对比

特性单向链表双向链表
遍历方向仅能正向遍历可双向遍历
节点结构data + nextdata + prev + next
插入删除删除需遍历找前驱(O(n))直接操作前驱节点(O(1))
内存占用较小(少一个指针)较大(多一个指针)
适用场景简单线性数据,内存紧张需要频繁查找前驱或反向遍历

五、嵌入式开发建议

  1. 资源受限系统

    • 优先考虑单向链表节省内存

    • 静态分配节点内存池避免碎片

  2. 实时性要求高

    • 双向链表删除操作更高效

    • 可考虑使用循环双向链表

  3. 调试技巧

    bash

    gdb ./your_program
    (gdb) b DouLinkList.c:100  # 在指定行设断点
    (gdb) p *node              # 查看节点内容
    (gdb) bt                   # 查看调用栈
  4. 性能优化

    • 维护尾指针加速尾插操作

    • 使用内存池预分配节点

http://www.dtcms.com/wzjs/166634.html

相关文章:

  • 珠海网站建设的公司哪家好建设网官方网站
  • 服务器网站域名系统装置秦皇岛网站seo
  • 网站后台 设计谷歌的推广是怎么样的推广
  • html5购物网站模板seo应用领域有哪些
  • 自助建站平台哪家好手机百度最新正版下载
  • 黑龙江建设网官方网站特种作业优化网站推广教程整站
  • 医院做网站需要多少钱成人英语培训
  • b2b网站建设怎么做百度搜索资源平台token
  • 论坛网站制作费用虞城seo代理地址
  • 手机网站进不去怎么解决江门百度seo公司
  • 网站做301将重定向到新域名在哪里推广比较好
  • 扬中网站优化公司北京seo关键词排名优化软件
  • 做门户网站需要准备什么我的百度网盘登录入口
  • 网站收录就是没排名网络推广公司主要做什么
  • 网站建设中高低端区别百度网站禁止访问怎么解除
  • 免费网站源码博客南宁百度推广seo
  • 医院网站建设价格海东地区谷歌seo网络优化
  • 网站跳出率是什么意思互联网推广方案怎么写
  • 音乐网站的制作巨量引擎广告投放平台登录入口
  • 正邦做网站吗创建网址链接
  • 北京市建设城乡建设委员会网站推广网站平台
  • 沧州企业网站制作的天津百度seo排名优化
  • 一级a做爰片免费网站性恔东莞做网站推广
  • 灵璧做网站的公司互联网金融营销案例
  • 山东广饶建设银行网站西安seo诊断
  • 潍坊微信网站开发品牌推广方案怎么写
  • 做计算机网站有哪些功能石家庄疫情最新消息
  • 网站开发客户端网站你应该明白我的意思吗
  • 登录深圳住房和建设局网站凡科网站官网
  • 广州网站app制作公司优就业seo