C语言线性表
顺序存储结构
地址计算方法
结构代码
#define MAXSIZE 20 //分配起始储存空间大小
typedef int ElemType //数据类型根据实际情况而定
typedef struct
{
ElemType data[MAXSIZE]; //数组储存数据元素,最大值为MAXSIZE
int length; //线性表当前长度
}
地址计算方法
在C语言中,数组是0开始第一个下标的,即第i个元素储存在数组下标为i-1的位置,假设每个数据元素占用B个储存单元,那么对于第i个数据元素Ai的储存位置可以由第一个元素算出,即
LOC(Ai)=LOC(A1)+(i-1)xB
插入与删除
首先要有一个程序,能获得元素。
获得元素操作
#define OK 1
#define error 0
#define ture 1
#define false 0
typedef int Status
//假定顺序线性表已经存在
Status getelem(sqlist L,int i,ElemType *e )
{
if(L.length==0 || i<1 || i>L.length) //处理出错情况
return error;
*e=L.data[i-1]; //把元素值通过指针赋值给e
return OK; //读取成功,返回ok,数据储存在e中
}
插入与删除操作
插入操作思路:
- 如果插入位置不合理,提示异常
- 如果线性表长度大于等于数组长度,则提示异常或者动态增加容量
- 从最后一个元素开始向前遍历到第i个位置,分别将它们向后移动一个位置
- 将要插入的元素填进i处
- 表长加1
Status ListInsert(sqlist *L,int i,ElemType e)
{
int k;
if(L->length==MAXSIZE) //线性表已满
return error;
if(i<1 || i > L.length) //不在表的范围内
return error;
if(i<=L->length) //插入元素不在表尾
{
for(k=L->length;k>=i-1;k--) //从后往前遍历
L.data[k+1]=L.data[k];
}
L.data[i]=e; //插入元素e
L->length++; //表长加1
return OK;
}
删除操作思路
- 如果删除位置不合理,则抛出异常
- 取出删除元素
- 从删除元素的位置开始向后遍历,使它们向前移动一位
- 表长减1
Sratus ListDelete(sqlist *L,int i,ElemType *e)
{
int k;
if(i>MAXSIZE || i<1 || i> L->length || L->length==0) //处理异常
return error;
*e=L->data[i-1]; //取出要删除的元素
if(i<L->length) //不在表尾
{
for(k=i;k<L->length;k++)
L.data[k-1]=L.data[k]; //向前移动
}
L->length--; //表长减1
return OK;
}
优缺点
优点:无需为表示表中元素之间的逻辑关系而增加额外的存储空间。可以快速地存取表中任一位置的元素
缺点:插入和删除操作需要移动大量的元素,当线性表长度变化较大时,难以确定存储空间的容量
链式存储结构
单链表
结构代码
typedef struct Node
{
ElemType data; //数据
struct node * next; //结构体指针
}Node;
typedef struct Node* LinkList; //用LinkList代替struct Node*
头指针与头节点
链表的第一个结点的存储位置叫做头指针(头指针无论如何也不为空)
。头节点是单链表的第一个结点前附加的一个结点。
读取操作
思路:
- 创建一个结点p指向链表的第一个结点,初始化j=1
- 当j<i时,遍历链表,让p不断向后移动,指向下一个结点,j累加1
- 若超出了链表范围,则说明第i个元素不存在,处理错误
- 否则查找成功,返回此时p节点的数据
Status getelem(LinkList L,int i,ElemType*e)
{
LinkList p;
p=L->next; //让p指向链表的第一个结点
int j=1;
if(j<i && p)
{
p=p->next; //遍历
++j;
}
if(!p || j>i) //第i个元素不存在
return error;
*e=p->data; //读取数据
return OK;
}
结点p的值就是结点p的地址
插入操作
思路:
- 声明一结点p指向链表的第一个结点,初始化j从1开始
- 当j<i时,遍历链表,让p的指针向后移动,j累加一
- 若到了链表末尾p为空,则说明第i个元素不存在
- 否则查找成功,在系统中生成一个空结点s
- 将元素e赋值给空结点 即s.data=e
- 然后将结点s插入 ,s.next=p.next; p.next=s;
- 返回成功
Status ListInsert(LinkList * L,int i,ElemType e) //实参应该为&L,二级指针
{
Linklist p,s;
p=*L;
int j=1;
if(p && j<i) //遍历
{
p=p->next; //修改指针本身
++j;
}
if(!p || j>i)
return error;
s=(LinkList)malloc(sizeof(Node)); //创建一个空结点s
s->data=e;
s->next=p->next;
p->next=s;
return OK;
}
删除操作
思路:
8. 声明一结点p指向链表的第一个结点,初始化j从1开始
9. 当j<i时,遍历链表,让p的指针向后移动,j累加一
10. 若到了链表末尾p为空,则说明第i个元素不存在
11. 否则查找成功,将要删除的结点p.next赋值给q,q=p.next
12. 单链表删除标准语句 p.next=q.next;
13. 将q结点的数据赋值给e,返回
14. 释放q结点
15. 返回成功
Status ListDelete(sqlist *L,int i,ElemType *e)
{
int j=1;
LinkList q;
LinkList p;
p=*L;
if(p && j<i)
{
p=p->next;
++j;
}
if(!p || j>i)
return error;
q=p->next;
p->next=q->next;
*e=q->data;
free(q); //释放结点q
return OK;
}
单链表的整表创建
思路一(表头插队法):
- 声明一个结点p和计数器变量i
- 初始化空链表L
- 让L的头结点指向NULL,即建立一个带头结点的单链表
- 循环:生成一新节点赋值给p,随机生成一数字赋值给p的数据域p.data,将p插入到头结点与前一新结点之间
void CreatListhead(LinkList *L,int n)
{
LinkList p;
int i;
srand(time(0));
*L=(LinkList)malloc(sizeof(Node));
(*L)->next=NULL; //建立一个带头结点的单链表
for(i=0;i<n;i++)
{
p=(LinkList)malloc(sizeof(Node));
p->data=rand()%100+1;
p->next=(*L).next; //插入到表头
(*L).next=p;
}
}
尾插法
void CreatListhead(LinkList *L , int n)
{
int i;
LinkList p,q;
srand(time(0));
*L=(LinkList)malaoc(sizeof(Node));
q=*L; //q为指向尾部的结点
for(i=0;i<n;i++)
{
p=(LinkList)malloc(sizeof(Node));//新结点
p->data=rand()%100+1; //随机数赋值
q->next=p; //尾部结点指针指向新插入的结点
q=p; //将当前的结点定义为尾部结点
}
q.next=NULL; //尾部结点指针为空,当前链表结束
}
单链表的整表删除
思路:
- 声明一结点p和q
- 将第一个结点赋值给p
- 循环:将下一结点赋值给q,释放p;将q赋值给p
Status ClearList(Linklist *L)
{
LinkList p,q;
p=(*L)->next; //p指向第一个结点
while(p) //没到表尾
{
q=p->next;
free(p);
p=q;
}
(*L)->next=NULL; //设置头结点指针域为空
return OK;
}
后面的不想写了
本文详细介绍了C语言中线性表的两种主要存储结构——顺序存储结构和链式存储结构。阐述了顺序存储结构的地址计算方法、插入与删除操作及优缺点,并深入探讨了链式存储结构中的单链表,包括头指针与头节点的概念、基本操作实现,以及单链表的创建和删除等。
2683

被折叠的 条评论
为什么被折叠?



