一、线性表——> 顺序存储 ——> 数组
开辟一块连续的内存来存储数据,(数据之间,逻辑相邻,物理地址相邻 )a[1] a[2] ==> 数组 int a[10] = {…}
//顺序表结构设计
typedef struct {
ElemType *data;//ElemType类型根据实际情况而定,这里假设为int
int length;
}Sqlist;
// 顺序表 初始化
int InitList(Sqlist *L){
//为顺序表分配一个大小为MAXSIZE 的数组空间
L->data = malloc(sizeof(ElemType) * MAXSIZE);
if(!L->data) exit(0);//存储分配失败退出
L->length = 0;//空表长度为0
return 1;
}
// 顺序表的插入 ==> 在顺序表的i位置插入e。起点从1开始,不是0。
int ListInsert(Sqlist *L,int i,ElemType e){
//i值不合法判断
if((i<1) || (i>L->length+1)) return ERROR;
//存储空间已满
if(L->length == MAXSIZE) return ERROR;
//插入数据不在表尾,则先移动出空余位置
if(i <= L->length){
for(int j = L->length-1; j>=i-1;j--){
//插入位置以及之后的位置后移动1位
L->data[j+1] = L->data[j];
}
}
L->data[i-1] = e;//将新元素e 放入第i个位置上
++L->length;//长度+1;
return 1;
}
//顺序表的取值 读取第i个元素
Int temp = L->data[i-1];
//顺序表删除 ==> 删除第i个数据
int ListDelete(Sqlist *L,int i){
//线性表为空
if(L->length == 0) return 0;
//i值不合法判断
if((i<1) || (i>L->length+1)) return 0;
for(int j = i; j < L->length;j++){
//被删除元素之后的元素向前移动 ==》 覆盖第i个元素
L->data[j-1] = L->data[j];
}
//表长度-1;
L->length --;
return 1;
}
//清空顺序表 顺序线性表L已存在。操作结果:将L重置为空表 */
int ClearList(Sqlist *L) {
L->length=0;
return 1;
}
//顺序表查找元素并返回位置 (L已存在)
int LocateElem(Sqlist L,ElemType e)
{
if (L.length==0) return 0;
int I;
for(i=0;i<L.length;i++) {
if (L.data[i]==e)
break;
}
if(i>=L.length) return 0;
return I+1;
}
二、单链表——>线性表的链式存储,在内存中是不连续的
对于非空的线性表和线性结构特点:
- 存在唯一 被称为“第一个”的数据元素
- 存在唯一 被称为“最后一个”的数据元素
- 存在唯一 被称为“第一个”的数据元素
一对一,有头尾,有前驱和后继。
单链表节点
//定义结点
typedef struct Node{
ElemType data; //数据域
struct Node *next;//带有后继的指针域
}Node;
typedef struct Node * LinkList;//
单链表逻辑状态——带有头结点的链表(头结点数据域为NULL)
//初始化单链表线性表 指针L指向头结点
int InitList(LinkList *L) {//*L == Node **L
*L = (LinkList)malloc(sizeof(Node)); //产生头结点,并使用L指向此头结点
if(*L == NULL) return 0; //存储空间分配失败
(*L)->next = NULL;//将头结点的指针域置空
return 1;
}
单链表插入——逻辑
//单链表插入 在list 第i位置插入元素e
int ListInsert(LinkList *L,int i,ElemType e){
int j = 1;
LinkList p,s;
p = *L;
while (p && j<i) { //寻找第i-1个结点
p = p->next;
++j;
}
//第i个元素不存在
if(!p || j>i) return 0;
s = (LinkList)malloc(sizeof(Node));//生成新结点s
s->data = e;//将e赋值给s的数值域
s->next = p->next; //将p的后继结点赋值给s的后继
p->next = s; //将s赋值给p的后继
return 1;
}
单链表删除元素 —逻辑
//单链表删除元素 删除L的第i个数据元素,并用e返回其值
int ListDelete(LinkList *L,int i,ElemType *e){
int j = 1;
LinkList p,q;
p = *L;
while (p && j<i) {//查找第i-1个结点,p指向该结点
p = p->next;
j += 1;
}
if (!(p->next) || (j>i-1)) return 0; //当i>n 或者 i<1 时,删除位置不合理
q = p->next;//q指向要删除的结点
p->next = q->next;//将q的后继赋值给p的后继
*e = q->data; //将q结点中的数据给e
free(q);//让系统回收此结点,释放内存;
return 1;
}
**单链表取值 **
//单链表取值 获取第i个元素, 用e返回L中第i个数据元素的值
int GetElem(LinkList L,int i,ElemType *e){
int j = 1;
LinkList p;
//p不为空,且计算j不等于i,则循环继续
while (p && j<=i) {
p = p->next; //p指向下一个结点
++j;
}
if(!p || j < i) return 0;//如果p为空或者j>i,则返回0
*e = p->data;//e = p所指的结点的data
return 1;
}
单链表前插入法 —逻辑
//单链表前插入法 随机产生n个元素值,建立带表头结点的单链线性表L
void CreateListHead(LinkList *L, int n){
LinkList p;
//建立1个带头结点的单链表
*L = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL;
for(int i = 0; i < n;i++) {//循环前插入随机数据
p = (LinkList)malloc(sizeof(Node));//生成新结点
p->data = i; //i赋值给新结点的data
p->next = (*L)->next;//p->next = 头结点的L->next
(*L)->next = p; //将结点P插入到头结点之后;
}
}
单链表后插入法
//单链表后插入法 随机产生n个元素值,建立带表头结点的单链线性表L
void CreateListTail(LinkList *L, int n){
LinkList p,r;
//建立1个带头结点的单链表
*L = (LinkList)malloc(sizeof(Node));
//r指向尾部的结点
r = *L;
for (int i=0; i<n; i++) {
p = (Node *)malloc(sizeof(Node)); //生成新结点
p->data = I;
r->next = p;//将表尾终端结点的指针指向新结点
r = p; //将当前的新结点定义为表尾终端结点
}
//将尾指针的next = null
r->next = NULL;
}
链表结构与顺序存储结构对比
存储分配方式:
- 顺序存储结构用一段连续的存储单元依次存储性表的数据元素。
- 单链表采用链式存储结构,用一组任意的存储单元存放线性表的数据元素。
时间性能:
- 查找——顺序存储O(1), 单链表O(n)。
- 插入和删除—— 存储结构需要平均移动半个表长的元素,时间O(n);单链表查找某位置后的指针后,插入删除为O(1)。
空间性能:
- 顺序存储结构需要预先分配存储空间,分太大,浪费空间,分小了,易溢出。
- 单链表不需要预先分配存储空间,只要有就可以分配,元素个数不受限制。
网友评论