线性表的概念
线性表是零个或多个数据元素的有限序列,并且线性表中的元素类型必须相同,线性表在物理存储上可以分为顺序存储结构和链式存储结构。
顺序存储结构:在内存空间中开辟一片连续的空间,然后把数据有序进行存储的一种方式。线性表的顺序存储结构类似于c语言中的数组,但两者的差别在于数组的长度是基本不变的,数组在申请内存空间的时候就已经确定其大小,而线性表的长度代表当前的元素个数,线性表的长度随元素的增删而动态变化。线性表的长度<=线性表的最大容量,即:线性表的当前长度<=数组的长度
链式存储结构:单链表不需要用地址连续的存储单元来实现,因为它不要求逻辑上相邻的两个数据元素物理上也相邻。单链表的每个结点包括指针域 (存放下一个结点的位置信息)和数据域(存放数据),它是通过链建立起数据元素之间的逻辑关系,因此对线性表的插入和删除不需要移动数据元素,只需要修改链。
线性表的顺序存储结构思路与代码
-
顺序存储结构的三大属性
1.数据类型Data
2.线性表的最大容量MaxSize
3.线性表的当前长度lengthconst int MaxSize=1e8; typedef int Elemtype;//Elemtype代表元素类型,这里用的int struct sqlist { Elemtype data[MaxSize]; int length; }sqlist;
-
顺序结构的删除和插入
1.插入元素:判断异常,将元素插入到线性表中,插入元素位置后的所有元素后移,链表长度加一。
2.删除元素:判断异常情况,将元素从线性表中删除后,删除元素位置后面的所有元素往前移,线性表长度减一。
#include<stdio.h>
#include<malloc.h>
const int MaxSize=1e8;
typedef int Elemtype;//Elemtype代表元素类型,这里用的int
typedef struct
{
Elemtype data[MaxSize];
int length;
}sqlist;
bool listinsert(sqlist *L,int x,Elemtype e)//x代表插入元素位置
{
int j;
if(L->length==MaxSize) return false;//判断是否在最大容量内
if(x<1||x>L->length+1) return false;//判断插入位置是否正常
if(x<L->length)//判断位置是否在尾部
for(j=L->length-1;j>=x-1;j--)
L->data[j+1]=L->data[j];
L->data[x-1]=e;
L->length++;
return true;
}
bool listdelete(sqlist *L,int x,Elemtype *e)
{
int j;
if(L->length==0) return false;//判断是否为空
if(x<1||x>L->length) return false;//判断删除位置是否正常
*e=L->data[x-1];
if(x<L->length)//判断位置是否在尾部
for(j=x;j<L->length;j++)
L->data[j-1]=L->data[j];
L->length--;
return true;
}
int main()
{
int n,i,k;
Elemtype e;
sqlist *L=(sqlist*)malloc(sizeof(sqlist));
printf("输入起始线性表有n个元素\n");
scanf("%d",&n);
printf("接着输入n个元素\n");
for(i=1;i<=n;i++)
{
scanf("%d",&e);
if(!listinsert(L,i,e)) printf("插入异常\n");
}
printf("输入你想要删除元素的位置\n");
scanf("%d",&k);
if(listdelete(L,k,&e)) printf("你删除的元素是%d\n",e);
else printf("删除异常\n");
printf("表中元素有\n");
for(int i=0;i<L->length;i++) printf("%d ",L->data[i]);
return 0;
}
线性表的链式存储结构思路与代码
- 链式存储结构的两大属性
- 数据域data
- 指针域next
- 链式结构的插入和删除
-
插入元素:在单链表LL的某个结点q之后插入一个新节点的基本过程是:首先找到正确位置q,然后申请新结点p的结点信息赋值,最后将p插在q之后。
核心代码:p->next=q->next;
q->next=p; -
删除元素: 声明两人指针变量p,q一个用于工作指针,一个用于临时存储信息。把第一个结点赋值给q,然后循环进行,直到cnt等于传入值,将下一个结点赋值给p,p->Next=q->Next;然后释放q。
核心代码:q=p->next;
p->next=q->next;
free(q);#include<stdio.h> #include<stdlib.h> typedef struct LNode *linklist;//给结构题起别名 struct LNode{//同样的这里也空用elemtype来控制元素类型,这里就用的int int data; linklist next; }; linklist listcreate() { linklist ll=(linklist)malloc(sizeof(linklist)); ll->next=NULL; ll->data=-1; return ll; } void listinsert(linklist L,int x,int i) { linklist p,q; int cnt=0; q=L; while(q&&cnt<i-1)//查找位序为i-1的结点 { q=q->next; cnt++; } if(q==NULL||cnt!=i-1)// 所找结点不在L中 { printf("插入位置异常\n"); exit(0); } else { p=(linklist)malloc(sizeof(linklist)); /*申请、填装结点*/ p->data = x; p->next = q->next; q->next = p; return ; } } bool listdelete(linklist L,int i) { linklist p,q; int cnt=0; q=L; while(q&&cnt<i-1) { q=q->next; cnt++; } if(q==NULL||cnt!=i-1||q->next==NULL) { printf("删除位置错误\n"); return false; } else { p=q->next; q->next=p->next; free(p); return true; } } int main() { linklist aa,bb; int i=0,index; aa=bb=listcreate(); printf("请输入多个数,以空格为区分,换行结束\n"); while(true) { int x; scanf("%d",&x); char ch=getchar();//读取空格 i++; listinsert(aa,x,i); if(ch=='\n') break;//如果数字后的元素是换行符,就跳出循环 } aa=bb; printf("输入删除元素的位序:\n"); scanf("%d",&index); if(listdelete(aa,index)) printf("删除成功\n"); aa=bb; aa=aa->next;//头结点无意义,跳过头结点 while(aa) { printf("%d ",aa->data); aa=aa->next; } return 0; }
顺序存储和链式存储的优缺点:
- 存储分配方式:顺序存储采用连续存储的单元进行存储,而链表采用一组任意存储单元进行存储。
- 时间性能:
- 查找:顺序存储O(1) ,链表 O(n);
- 插入与删除:顺序存储O(n),链表 O(1);
- 空间性能:顺序存储结构需要分配存储空间,链表不需要分配,元素个数不受限制。