数据结构简单话(一)线性表
前言
本菜鸟笔者打算入门一下数据结构,在学习过程中通过自己简单话术总结相关基础知识要点,希望能帮助同样在入门的小伙伴们快速了解相关基础知识的轮廓,然后根据知识点再进一步的学习和理解。整个系列采用c语言来实现,代码会提供注释,方便理解实现思路。
逻辑结构
线性表是0个或多个的有穷序列, 是的前驱,是的后继,除了首尾结点以外每个结点元素都有且只有一个前驱和一个后继(类似于现实生活中排队)。
物理存储结构
一、顺序表
-
概念:采用一组相邻且连续的存储空间存储元素。即:存储一个元素需要2个单位地址空间,从1号开始存储,则第二个元素存储首地址为3号,以此类推。代码实现中常用数组作为顺序表元素的存储。
-
优缺点
- 优点:方便查找,确定首地址就可以查找任意下标的元素。由此可以随机存取。
- 缺点:不易于插入删除,由于顺序表中元素地址是相邻的,当插入或者删除一个元素后,修改位置之后的所有元素都需要移动,空间开销大(类比排队中一个人出或者插入到队伍中,后面的所有人都需要向前或向后移动)
-
代码实现(初始化增删改查)
#include<stdlib.h> #include<stdio.h> #define MAXMIUM 100 //定义数组容量最大值 /*结构体*/ typedef struct SeqList { int element[MAXMIUM];//存放整型数据的数组 int n;//数组元素个数 }SeqList; /*初始化,创建一个顺序表*/ SeqList *createNullSeq() { SeqList *list = (SeqList *)malloc(sizeof(SeqList)); if (list == NULL) { printf("wrong"); } else { list->n = 0;//初始化的数组内没有元素,所以n=0 } return list; } /*在指定下标位置插入元素*/ int insert(SeqList* list , int data,int index){ if(list->n < MAXMIUM && index<=list->n){//插入前数组个数不能达到上限,下标需要在有效范围内 int i; for(i=list->n-1;i>=index;i--){//当前插入元素的位置和位置后的元素都需要往后移动一位 list->element[i+1] = list->element[i]; } i++; list->element[i] = data; list->n++; return 1; } return 0; } /*删除指定位置的元素*/ int delete(SeqList* list,int index){ if(index<=list->n-1&&index>=0){//跟插入类似,判断有效条件 for(int i=index;i<list->n-1;i++){//删除的位置以及后面的元素都需要往前移动一格 list->element[i] = list->element[i+1]; } list->n--; return 1; } return 0; } /*简单线性表判空*/ int isNull(SeqList* list){ return list->n==0?1:0; } /*查找元素*/ int locate_seq(SeqList* list,int data){ if(list->n==0){ return -1; } for(int i=0;i<list->n;i++){ if(list->element[i]==data){ return i; } } return -1; } /*获得指定下标的元素*/ int find(SeqList* list,int x){ if(x>=0||x<list->n){ return list->element[x]; } return -1; }
二、链表
-
原理
顺序表插入删除需要大量空间损耗(因为需要移动),所以可以采用链表的方式减少损耗。每个结点元素在存储元素信息时(数据域),还需要额外存储一个指针域,用于存储指向下一个结点的地址。这样相邻结点之间的地址无需相邻。插入删除时只需要修改相关指针域即可。
-
优缺点
- 优点:插入删除空间代价小,只需要直接修改指针域。
- 缺点:查找麻烦,每次查找都需要从头结点遍历。
-
代码实现(初始化增删改查)
#include <stdio.h> #include <stdlib.h> typedef struct PNode { struct PNode *next; int data; } PNode; PNode *createNullNode() { PNode *node = (PNode *)malloc(sizeof(PNode)); if (node == NULL) { printf("wrong"); return NULL; } node->next = NULL; node->data = 0; return node; } /*带头结点插入*/ int insertNode(PNode *list, int i, int data) { if (list == NULL) { printf("null"); return 0; } int p = 0; while (list->next != NULL) { if (p != i) { list = list->next; p++; }else{ break; } } if (p == i) { PNode *temp = list->next; PNode *node = createNullNode(); node->next = temp; node->data = data; list->next = node; return 1; } printf("out of range"); return 0; } /*带头结点删除第一个值为x的结点*/ int delete(PNode *list,int x){ if(list==NULL){ printf("list is null"); return 0; } while(list->next!=NULL&&list->next->data!=x){ list = list->next; } if(list->next!=NULL&&list->next->data==x){ PNode* temp = list->next; list->next = temp->next; temp->next = NULL; free(temp); return 1; } printf("no found %d",x); return 0; } /*通过下标查找元素,带头结点*/ PNode *find(PNode* list,int i){ if(list==NULL){ printf("null list "); return NULL; } int cursor = 0; while(list->next!=NULL&&cursor!=i){ list = list->next; cursor++; } if(cursor==i){ printf("find %d",list->next->data); return list->next; } printf("out of range"); return NULL; } /*判空*/ int isNull(PNode* list){ return list==NULL?1:list->next==NULL?1:0; } int main() { PNode *head = createNullNode(); int flag = isNull(head); printf("%d\n",isNull(head)); insertNode(head,0,1); insertNode(head,1,2); insertNode(head,2,3); insertNode(head,3,4); insertNode(head,2,77); // find(head,2); printf("%d",isNull(head)); }
总结
- 链表方便增删,顺序表方便查找
- 链表的增删主要通过修改指针,顺序表增删主要通过移动元素。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 上周热点回顾(2.17-2.23)
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)