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

Day03_数据结构(手写)

01.数据结构画图

02.

//11.按值查找返回位置                      
int search_value(node_p H,int value)       
{                                          if(H==NULL){                           printf("入参为空.\n");             return -1;                         }                                      if(empty_double(H)){                   return -2;                         }                                      int i;                                 node_p p=H->next;                      for(i=0;p!=NULL;i++,p=p->next)         {                                      if(p->data==value){                return i;                      }                                  }                                      }                                          

//12.按位置修改元素                                 
void update_pos(node_p H,int pos,int new_value)     
{                                                   if(H==NULL){                                    printf("入参为空.\n");                      return;                                     }                                               if(empty_double(H)){                            printf("双项链表为空,没有值可以修改.\n");   return;                                     }                                               if(pos<0){                                      return;                                     }                                               int i;                                          node_p p;                                       for(i=0,p=H->next;i<pos;i++,p=p->next){         p->data=new_value;                          }                                               }                                                   

02.自己实现双向循环链表的代码
a.创建
b.创建结点
c.头插
d.尾插
e.按位置插入
f.头删、尾删、按位置删除
g.按位置查找返回值

]main.c

#include "dloop.h"
int main()
{node_p H=(node_p)create_dloop();//1.头插printf("请输出头插的第一个数字双向链表:\n");insert_head(H,4);show(H);printf("请输出头插的第二个数字双向链表:\n");insert_head(H,3);show(H);printf("请输出头插的第三个数字双向链表:\n");insert_head(H,2);show(H);printf("请输出头插的第四个数字双向链表:\n");insert_head(H,1);show(H);//2.尾插printf("请输出尾插的第一个数字双向链表:\n");insert_tail(H,5);show(H);printf("请输出尾插的第二个数字双向链表:\n");insert_tail(H,6);show(H);//3.按位置插入printf("请输出按位置插入双向链表:\n");insert_pos(H,3,77);show(H);//4.头删printf("请输出头删双向链表:\n");dele_head(H);show(H);//5.尾删printf("请输出头删双向链表:\n");dele_tail(H);show(H);//6.按位置删除printf("请输出按位置删除双向链表:\n");delete_pos(H,3);show(H);//7.按位置查找返回值int ret=search_value(H,2);printf("请输出按位查找的返回值%d:\n",ret);show(H);printf("销毁前:\n");printf("%p\n",H);free_loop(&H);printf("销毁后:\n");printf("%p\n",H);}

dloop.c

#include "dloop.h"
//1.创建双链表的空结点
node_p create_dloop()
{node_p H=(node_p)malloc(sizeof(node));if(H==NULL){printf("申请内存失败.\n");return NULL;}H->pri=H;H->next=H;H->len=0;return H;
}
//2.申请结点
node_p create_node(int value)
{node_p new=(node_p)malloc(sizeof(node));new->next=NULL;new->data=value;
}
//3.判空
int empty_dloop(node_p H)
{if(H==NULL){printf("入参为空.\n");return -1;}return H->next==H?1:0;
}
//4.头插
void insert_head(node_p H,int value)
{if(H==NULL){printf("入参为空.\n");return;}node_p new=create_node(value);new->next=H->next;new->pri=H;if(H->next!=NULL){H->next->pri=new;}H->next=new;H->len++;
}
//5.尾插
void insert_tail(node_p H,int value)
{if(H==NULL){printf("入参为空.\n");return;}int i;node_p new=create_node(value);node_p p=H;//1.找到了最后一个结点的位置while(p->next!=H){p=p->next;}new->pri=p;new->next=H;p->next=new;H->pri=new;H->len++;
}
//6.按位置插入
void insert_pos(node_p H,int pos,int value)
{if(H==NULL){printf("入参为空.\n");return;}if(pos<0){printf("插入位置的数据不合理.\n");return;}int i;node_p p;for(i=1,p=H->next;i<pos-1;i++,p=p->next){if(p==H){printf("位置不合理.\n");return;}}if(p==H){printf("位置不合理.\n");return;}node_p new=(node_p)create_node(value);new->next=p->next;new->pri=p;if(p->next!=H){p->next->pri=new;}p->next=new;H->len++;	
}
//7.输出
void show(node_p H)
{if(H==NULL){printf("入参为空.\n");return;}if(empty_dloop(H)){printf("双向循环链表为空,无输出.\n");return;}node_p p=H->next;while(p!=H){printf("%d->",p->data);p=p->next;}printf("NULL\n");
}
//8.头删
void dele_head(node_p H)
{if(H==NULL){printf("入参为空.\n");return;}if(empty_dloop(H)){printf("循环双链表为空,无数据可删除.\n");return;}node_p dele=H->next;//判断是否就一个数据if(dele->next!=H){dele->next->pri=H;}H->next=dele->next;free(dele);H->len--;
}
//9.尾删
void dele_tail(node_p H)
{if(H==NULL){printf("入参为空.\n");return;}node_p p=H;while(p->next!=H){p=p->next;}p->pri->next=H;H->pri=p->pri;free(p);H->len--;
}
//10.按位置删除
void delete_pos(node_p H,int pos)
{if(H==NULL){printf("入参为空.\n");return;}if(empty_dloop(H)){printf("双向链表为空.\n");return;}node_p p;int i;for(i=1,p=H->next;i<pos;i++,p=p->next){if(p==H){printf("位置不合理.\n");return;}}if(p==H){printf("位置不合理.\n");return;}//1.pos+1结点的前驱指向pos-1结点if(p->next!=H){p->next->pri=p->pri;}//2.pos-1结点的后继指向pos+1结点p->pri->next=p->next;free(p);H->len--;
}//11.按位置查找返回值
int search_value(node_p H,int pos)
{if(H==NULL){printf("入参为空.\n");return -1;}if(empty_dloop(H)){printf("双向循环链表为空.\n");return -2;}int i;node_p p;for(i=1,p=H->next;i<pos;i++,p=p->next){if(p==H){printf("位置不合理.\n");return -3;}}if(p==H){printf("位置不合理.\n");return -3;}return p->data;
}
//12.释放链表
void free_loop(node_p *H)
{if(H==NULL||*H==NULL){printf("入参为空.\n");return;}while((*H)->next!=(*H)){dele_head(*H);}free(*H);*H==NULL;
}

dlloop.h

#ifndef __DLOOP_H__
#define __DLOOP_H__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct node
{union{int len;int data;};struct node *pri;struct node *next;
}node,*node_p;node_p create_dloop();
node_p create_node(int value);
int empty_dloop(node_p H);
void insert_head(node_p H,int value);
void insert_tail(node_p H,int value);
void insert_pos(node_p H,int pos,int value);
void show(node_p H);
void dele_head(node_p H);
void dele_tail(node_p H);
void delete_pos(node_p H,int pos);
int search_value(node_p H,int pos);
void free_loop(node_p *H);#endif

03.整理链表和顺序表的优缺点

链表和顺序表是两种常见的数据存储结构,它们各自有不同的优缺点,下面为你详细介绍:

顺序表

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般采用数组来实现。

优点
  1. 随机访问效率高:通过数组下标可以直接访问任意位置的元素,时间复杂度为 $O(1)$。例如,在一个长度为 $n$ 的数组 arr 中,访问 arr[i] 能快速定位到对应元素。
  2. 缓存局部性好:由于顺序表的元素在内存中是连续存储的,计算机在访问元素时,会把相邻的数据也加载到缓存中,后续访问相邻元素时能更快获取,提高了访问效率。
  3. 空间利用率高:顺序表不需要额外的指针来维护元素之间的关系,只存储数据本身,因此空间利用率相对较高。
缺点
  1. 插入和删除操作效率低:在顺序表中间或开头插入、删除元素时,需要移动大量后续元素,平均时间复杂度为 $O(n)$。例如,在数组中间插入一个元素,需要将插入位置之后的所有元素依次向后移动一位。
  2. 空间扩展不便:当顺序表需要扩容时,通常需要重新分配一块更大的内存空间,并将原有的数据复制过去,操作比较耗时。而且如果一次性分配过大的空间,可能会造成内存浪费;分配过小,又需要频繁扩容。
  3. 内存分配要求高:顺序表要求内存空间必须连续,当需要存储大量数据时,可能难以找到足够大的连续内存空间。

链表

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。常见的链表有单链表、双向链表和循环链表。

优点
  1. 插入和删除操作效率高:在链表中插入或删除元素,只需要修改相邻节点的指针,不需要移动大量元素,时间复杂度为 $O(1)$(前提是已经找到插入或删除的位置)。例如,在单链表中插入一个新节点,只需修改前一个节点的指针和新节点的指针。
  2. 空间动态分配:链表的节点是在需要时动态分配内存的,不需要预先分配大量连续的内存空间,避免了内存浪费和分配失败的问题。
  3. 内存利用率高:链表不需要连续的内存空间,只要有足够的零散内存,就可以创建链表节点,适合存储大量数据。
缺点
  1. 随机访问效率低:链表只能从表头开始依次遍历查找元素,访问第 $i$ 个元素的平均时间复杂度为 $O(n)$,无法像顺序表那样直接通过下标访问。
  2. 额外空间开销大:链表的每个节点除了存储数据本身,还需要额外的指针来指向下一个节点(双向链表还需要指向前驱节点),增加了空间开销。
  3. 缓存局部性差:由于链表的节点在内存中是分散存储的,访问元素时可能无法充分利用缓存,导致访问效率降低。

综上所述,顺序表适合随机访问频繁、数据量固定的场景;链表适合插入和删除操作频繁、数据量动态变化的场景。

相关文章:

  • rockylinuxapache和Linux服务配置
  • Python+pymysql中select count(*)/select *使用方式
  • 安装谷歌vue开发工具插件devtools支持vue2
  • linux内核-写时复制之实验+源码分析
  • Ajax 核心知识点全面总结
  • day40- 硬件学习之 51单片机II (中断处理)
  • 【MySQL】MySQL 数据库操作与设计
  • 网络编程TCP与UDP
  • 《开窍》读书笔记9
  • vulnhub-Matrix-Breakout 2 Morpheus
  • 网络NAT是什么
  • Go 语言中的条件判断和for 循环
  • 详解 MyBatis - Plus 服务层设计:让 CRUD 更高效、业务拓展更灵活——补充
  • ArrayList源码分析
  • Arrays.asList() 的不可变陷阱:问题、原理与解决方案
  • 全面理解 JVM 垃圾回收(GC)机制:原理、流程与实践
  • DHCP实战
  • Quick BI 自定义组件开发 -- 第三篇 echart 组件开发图表,使用动态数据
  • 知识图谱和知识库的区别:详细解读
  • react框架-路由的嵌套以及参数传递与编程化
  • 做网站用的服务器/seo优化是啥
  • 网页设计html和css代码/成都网站快速优化排名
  • 自己做游戏的网站/百度官方网平台
  • vps云主机可以做网站/推广专家
  • 优化网站内容的方法/产品如何做市场推广
  • 秦皇岛建设工程/站群优化公司