1.线性表的类型定义
线性表是最简单、也是最基本的一种线性数据结构。它有两种存储表示方法:顺序表和链表,它的主要基本操作是插入、删除和查找。
线性表是n(n>=0)个数据元素的有限序列,表中各个数据元素具有相同特性,即属同一数据对象,表中相邻的数据元素之间存在“序偶”关系。通常将线性表记做
(a1,a2, …,ai-1,ai,ai+1,…,an-1,an)
则表中ai-1领先于ai,ai领先于ai+1,称ai-1是ai的直接前驱元素,ai+1是ai的直接后继元素。当i=1,2,…,n-1时,ai有且仅有一个直接后继,当i=2,3,…,n时,ai有且仅有一个直接前驱.
线性表中的个数n(n>=0)定义为线性表的长度,n=0时称为空表。在非空表中每个数据元素都有一个确定的位置,如用ai表示数据元素,则i称为数据元素ai在线性表中的位序。
特征:
1.集合中必存在唯一的一个“第一元素”。
2.集合中必存在唯一的一个 “最后元素” 。
3.除最后一个元素之外,均有唯一的后继(后件)。
4.除第一个元素之外,均有唯一的前驱(前件)。
2.顺序表
在程序中,经常需要将一组(通常是同为某个类型的)数据元素作为整体管理和使用,需要创建这种元素组,用变量记录它们,传进传出函数等。一组数据中包含的元素个数可能发生变化(可以增加或删除元素)。
对于这种需求,最简单的解决方案便是将这样一组元素看成一个序列,用元素在序列里的位置和顺序,表示实际应用中的某种有意义的信息,或者表示数据之间的某种关系。
这样的一组序列元素的组织形式,我们可以将其抽象为线性表。一个线性表是某类元素的一个集合,还记录着元素之间的一种顺序关系。线性表是最基本的数据结构之一,在实际程序中应用非常广泛,它还经常被用作更复杂的数据结构的实现基础。
根据线性表的实际存储方式,分为两种实现模型:
1.顺序表,将元素顺序地存放在一块连续的存储区里,元素间的顺序关系由它们的存储顺序自然表示。
2.链表,将元素存放在通过链接构造起来的一系列存储块中。
在讲顺序表之前我们先来看一组数据:
int =1,2,3,4,5
1
如何把这组数据当作一个整体保存这组数据?
前面我们已经知道可以采用列表list,字典dict ,元祖等,但是在这里我们先不讨论使用这些高级的数据结构,我们就是用基本的数据结构int,float,char来讨论。
所以在这里引入内存的概念。
在内存中,是以字节Byte为单位的一个连续的存储空间,安存储单位来进行标识,往往进行存储数据的时候要多个存储单位来存的。
而上面的数据是整型,占4个字节,在内存当中一个字节是8位,所以一个整型是占位4Byte即32位(类型不同占存储单位大小不一样)。
3.链表
链表是一种物理存储单元上非连续、非顺序的存储结构。数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
线性表的顺序存储结构缺点是每一次插入和删除元素,大量元素的移动会导致时间效率低下。为了改进顺序存储结构的缺点,引入链式存储结构,即为链表。
链式存储结构的特点是用一组任意的存储单元来存储线性表中的数据元素。这样在插入和删除元素时,可以通过直接修改指针完成操作,时间效率大大提高。但因为链式存储结构的存储单元不连续,所以需要通过指针来访问它的后续元素。
为了表示每个数据元素与其直接后继数据元素之间的逻辑关系,我们需要存出一个其直接后继的存储位置。我们把存储数据元素信息的域成为数据域,把存储后继位置的域称为指针域,这两部分构成一个节点。
n个节点链接成一个链表,即为线性表的链式存储结构。因为每个节点只有一个指针域,所以又将这样的链表称为单链表。
代码
#include<stdio.h>
#include<stdlib.h>
typedef struct LinkList
{
int data;//数据域
struct LinkList* next;//指针域
}Link;
Link* InitList();
void HeadInsert(Link* node, int n);
void MidInsert(Link* node, int n, int i);
int find(Link* node, int n);
void delete(Link* node, int n);
void show(Link* node);
int main()
{
Link* node = InitList();
HeadInsert(node, 1);
HeadInsert(node, 2);
HeadInsert(node, 3);
HeadInsert(node, 4);
show(node);//输出4321
printf("\n");
MidInsert(node, 5, 1);
show(node);//输出45321
printf("\n");
int i = find(node, 2);
printf("%d\n", i);//输出3
delete(node, 3);
show(node);//输出4521
return 0;
}
/*初始化单链表*/
//创建一个头结点
Link* InitList()
{
Link* node = (Link*)malloc(sizeof(Link));
if (node == NULL)
printf("初始化函数已执行,内存分配失败\n");
else
node->next = NULL;
return node;
}
/*头插法*/
//在头结点后,其他结点前插入元素
//node:头结点,n:待插入元素,insert:待插入结点
void HeadInsert(Link* node, int n)
{
Link* insert = (Link*)malloc(sizeof(Link));
insert->data = n;
insert->next = node->next;
node->next = insert;
}
/*中间插入*/
//在第i个位置前插入一个元素n
//temp:临时指针,用于移动找位置,而不用移动头指针
void MidInsert(Link* node, int n, int i)
{
Link* insert = (Link*)malloc(sizeof(Link));
Link* temp = (Link*)malloc(sizeof(Link));
temp = node->next;
//将temp指向插入位置后的元素
int j = 0;
while (temp != NULL && j < i - 1)
{
temp = temp->next;
j++;
}
if (temp == NULL && i > j - 1)
printf("没有此位置,插入失败\n");
insert->data = n;
insert->next = temp->next;
temp->next = insert;
}
/*查找元素*/
//temp一直挨个向后移动,若发现有,则返回下标,直到指向空
int find(Link* node, int n)
{
Link* temp = (Link*)malloc(sizeof(Link));
temp = node->next;
int i = 0;
while (temp != NULL)
{
if (temp->data == n)
return i;
else
{
temp = temp->next;
i++;
}
}
return -1;
}
/*删除元素*/
void delete(Link* node, int n)
{
Link* temp = (Link*)malloc(sizeof(Link));
temp = node->next;
//找到删除元素下标,并把temp指向要删除结点的前一个结点
int i = find(node, n);
if (i == -1)
printf("没有此元素,删除失败\n");
else
{
int j = 0;
while (j < i - 1)
{
temp = temp->next;
j++;
}
//先保存要删除的结点,再改变指针指向
Link* FreeNode = temp->next;
temp->next = temp->next->next;
free(FreeNode);
}
}
/*展示数据元素*/
void show(Link* node)
{
Link* temp = (Link*)malloc(sizeof(Link));
temp = node->next;
while (temp != NULL)
{
printf("%d", temp->data);
temp = temp->next;
}
}