数据结构之线性表

线性表的抽象数据类型定义:

 

Date

线性表的数据对象集合为{A1, A2, ..., AN},每个元素的类型均为DateType 。其中除了第一个元素A1外,每一个元素有且只有一个直接前驱,除了最后一个元素AN外,每一个元素有且只有一个直接后继。数据元素之间的关系是一对一的关系。

operation InitList(* L);//初始化操作,建立一个空的线性表 ListEmpty(L);//若线性表为空,返回true,否则返回false ClearList(*L);//将线性表清空 GetElem(L, i, *e);//将线性表L中的第i个位置元素返回给e LocateElem(L, e);//将线性表L中查找与给定值e相等的元素,如果查找成功返回该元素在表中序号表示;否则返回0表示失败 ListInsert(*L, i, e);//在线性表L的第i个位置插入新元素e ListDelete(*L, i, *e);//删除线性表L中第i个元素,并用e返回其值 ListLength(L);//返回线性表L中元素的个素 endADT
 

线性表的顺序存储结构

 

代码示例:

#include<stdio.h> #define MAXSIZE 20 //存储空间初始化分配量 #define OK 1 #define ERROR 0 typedef int Status; //函数类型,返回OK, ERROR结果状态码 typedef int ElemType; //ElemType类型根据实际情况而定, 这里为int typedef struct Person { ElemType date[MAXSIZE]; //int类型数组,存储数据元素 int length = -1; //线性表当前长度 }SqList; Status GetElem(SqList L, int i, ElemType* e) //获得元素操作 { if (i < 0 || i >= L.length || L.length == 0) { return ERROR; } *e = L.date[i]; return OK; } Status ListInsert(SqList* L, int i, ElemType e) //插入元素操作 { if (L->length == MAXSIZE) { return ERROR; } if (i < 0 || i >= MAXSIZE) { return ERROR; } if (i < L->length ) //插入数据不在表尾 { for (int k = L->length; k >= i; k--) { L->date[k + 1] = L->date[k]; } } else { L->date[i] = e; } L->date[i] = e; L->length++; return OK; } Status Pint_List(SqList* L) //输出线性表 { int k = 0; for (int i = 0; i <= L->length; i++) { k = 1; printf("%d ", L->date[i]); } if (k == 1) return OK; else return ERROR; } Status ListDelete(SqList* L, int i, ElemType* e) //删除线性表第 i 个元素 { if (L->length == -1) return ERROR; if (i < 0 || i > L->length) return ERROR; *e = L->date[i]; if (i < L->length - 1) //如果删除不是线性表最后位置 { for (int k = i; k < L->length ; k++) { L->date[k] = L->date[k + 1]; } } L->length--; return OK; } int main() { SqList list1; for (int i = 0; i < 10; i++) { int insert_signal = ListInsert(&list1, i, i);//接受插入信号 if (insert_signal == OK) { printf("%d 插入成功!\n",i); } else { printf("%d 插入失败!\n", i); } } ListInsert(&list1, 10, 10); ListInsert(&list1, 9, 10); ListInsert(&list1, 1, 33); int print_signal = Pint_List(&list1);//接受输出信号 if (print_signal == OK) { printf("输出成功!\n\n"); } else { printf("输出失败!\n\n"); } int temp_nal; int delete_signal = ListDelete(&list1,1, &temp_nal); if (delete_signal == OK) { printf("成功删除:%d\n\n", temp_nal); print_signal = Pint_List(&list1); } else { printf("删除失败!\n\n"); } return 0; }
 

优点:

  • 无须为表示表中元素之间的逻辑关系而增加额外的存储空间
  • 可以快速的存取表中任一位置的元素
 

缺点:

  • 插入和删除操作需要移动大量元素
  • 当线性表长度变化较大时,难以确定存储空间的容量
  • 造成存储空间的“碎片”
 

线性表的链式存储结构

 

代码示例:

#include<stdio.h> #include<stdlib.h> int num = 0; typedef struct Node { int value; struct Node *next; }std; std *create_list() //创建一张空表 { std* head = NULL; return head; } std* Insert_list(std* head, int i, int elem)//插入操作 { std* p1 = NULL, *p2 = NULL ,* p3 = NULL; if (head == NULL) //判断链表是否为空 { p2 = (std*)(malloc(sizeof(std))); num++; p2->value = elem; p2->next = NULL; head = p2; return head; } if (i == 0 && head != NULL) //头插 { p2 = (std*)(malloc(sizeof(std))); num++; p2->value = elem; p2->next = head; head = p2; return head; } int j = 0; p1 = head; while (j < i && p1 != NULL) { p3 = p1; p1 = p1->next; j++; } if (p1 == NULL) //尾插 { p2 = (std*)(malloc(sizeof(std))); num++; p2->value = elem; p3->next = p2; p2->next = NULL; return head; } else //中插 { p2 = (std*)(malloc(sizeof(std))); num++; p2->value = elem; p3->next = p2; p2->next = p1; return head; } } std* Deletelist(std* L, int i, int* e)//删除操作 { int j = 0; std* p = L; std *p1 = NULL; if (i == 0)//头删 { L = p->next; num--; free(p); return L; } while (j < i && p) { p1 = p; p = p->next; j++; } if (p->next == NULL)//尾删 { p1->next = NULL; num--; return L; } else { p1->next = p->next;//中删 num--; } free(p); return L; } std* modifylist(std* L, int i, int e)//修改操作 { std* p = L; int j = 0; while (j < i && p) { p = p->next; j++; } p->value = e; return L; } void queryelem(std* L, int elem)//查找操作 { std* p = L; while (p) { if (p->value == elem) { printf("找到此元素:%d", elem); return 0; } p = p->next; } printf("表中无此元素!"); } void print_list(std* head)//打印链表 { if (head) { std* p = head; while (p) { printf("%d ", p->value); p = p->next; } printf("\n"); } else { printf("链表为空!"); } } int main() { std* head = create_list(); head = Insert_list(head, 0, 0); head = Insert_list(head, 1, 1); head = Insert_list(head, 2, 2); head = Insert_list(head, 3, 3); head = Insert_list(head, 4, 4); head = Insert_list(head, 5, 5); head = Insert_list(head, 6, 6); int a; print_list(head); printf("删除第一个元素:\n"); head = Deletelist(head, 0, &a); print_list(head); printf("删除第三个元素:\n"); head = Deletelist(head, 3, &a); print_list(head); printf("删除最后一个元素:\n"); head = Deletelist(head, 4, &a); print_list(head); printf("修改第3个元素值为2\n"); head = modifylist(head, 3, 2); print_list(head); printf("查找是否存在值为3的结点!\n"); queryelem(head, 3); return 0; }
 

优点:

  • 单链表在找出位置的指针后,插入和删除的时间复杂度仅为O(1)
  • 单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制
 

缺点:

单链表查找时间复杂度O(n)

 

循环链表

 

定义:

将单链表中终端结点的指针由空指针指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为循环链表

循环链表循环链表

 

双向链表

 

定义:

双向链表是在单链表的每一个结点中,在设置一个指向前驱结点的指针域

 

存储结构

typedef struct Node { int value; struct Node* prior; struct Node *next; }std;
 

插入操作:

双向插入双向插入

 

删除操作:

双向删除双向删除


__EOF__

本文作者夜雨闻铃
本文链接https://www.cnblogs.com/sugeek/articles/16609112.html
关于博主:编程菜鸟一只,希望每个今天胜过昨天,一步步走向技术的高峰!
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   sugeek  阅读(45)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示