C/C++实现线性表的顺序存储和链式存储及其增、删等操作

本文深入讲解线性表的基本概念,包括其性质、顺序存储和链式存储结构。探讨了线性表的抽象数据类型,以及如何通过数组和链表实现线性表的存储。详细介绍了线性表的基本操作,如初始化、查找、插入、删除和求表长。


[ 2020年7月6号]

一.线性表基本概念

1.基本概念

  • 线性表(List):零个或多个数据元素的有限序列
  • 性质①:第一个元素无前驱,最后一个元素无后继
  • 性质②:线性表的长度都是有限的
  • 性质③:在较复杂的线性表中,一个数据元素可以由若干个数据项组成,例如:
学号姓名性别
1CLAY
2Codes
31024
  • 线性表的抽象数据类型如下
ADT List
DATA 
	......
Operation
	InitList(&L): 初始化操作,建立一个空的线性表
	ListEmpty(L): 若线性表为空,返回True,否则返回False
	ClearList(&L): 清空线性表
	GetElem(L, i, *e): 查找线性表中第i个位置的元素并将值返还给e
	LocateElem(L, e): 在线性表中查找值为e的元素
	ListInsert(&L, i, e): 在线性表L中第i个位置插入值为e的新元素
	ListDelete(&L, i, *e): 删除线性表L中第i个位置的元素,并用e存储其值
	ListLength(L): 返回线性表L的的元素个数
endADT

2.数组和线性表的关系

  • 数组是物理结构,线性表是逻辑结构
  • 数据是线性表顺序存储的结果
  • 线性表不仅有顺序存储,还有链式存储两种物理结构

二.线性表的顺序存储结构

  • 定义:指的是用一段地址连续的存储单元依次存储线性表的数据元素。
  • 线性表顺序存储的结构代码
const int MAXSIZE = 20;     //分配存储空间
typedef int ElemType;
typedef struct
{
	/*注意:MAXSIZE是数组的最大长度,length是线性表的长度*/
	
	ElemType *data; //数组存储数据元素
	int length;     //线性表当前长度
	int size;       //顺序表当前容量
}SqList;
  • 地址计算方法:LOC(ai) = LOC(a1) + (n-1)*c
    其中LOC表示获取存储位置的函数,c表示一个数据元素占用的存储单元的个数。

  • 初始化操作

#define OK 1
#define ERROR 0
#define OVERFOLW -2
typedef int Status;

Status InitList(SqList &L)
{
	L.data = new ElemType[MAXSIZE];//给动态数组分配空间
	if(!L.data) exit(OVERFOLW);
	L.length = 0;//置表长为0
	L.size = MAXSIZE;
	renturn OK;
}
  • 获取元素操作
Status GetElem(SqList L,int i,ElemType *e)
{
	if(L.length == 0 || i < 1 ||i > L.length) //异常处理
		return ERROR;
	*e = L.data[i-1];      //i从1开始算,但是数组从0开始算,所以第i个位置对应数组下标i-1
	return OK;
}
  • 插入操作

算法思路啊如下:

1.如果插入位置不合适,抛出异常
2.如果线性表长度大于等于数组长度,动态增加容量
3.从最后一个元素开始向前遍历到第i个位置,分别将他们都向后移动一个位置
4.将插入的元素填入位置i处
5.表长加1
Status ListInsert(SqList &L,int i,ElemType e)
{
    ElemType *base;
    if(L.length == MAXSIZE)//异常处理
        return ERROR;
    if(i < 1 || i > L.length + 1)//异常处理
        return ERROR;
    if(L.length > L.size)//动态扩容
    {
        base = new ElemType;
        L.data = base;
        L.size += 1;
    }
    if(i <= L.length)//若插入的位置不在表尾
    {
        //在将要插入的位置后数据元素向后移动一位
        for(int j = L.length - 1;j >= i-1;--j)
            L.data[j+1] = L.data[j];
    }
    L.data[i-1] = e;//插入新元素
    L.length++;//表长加一
    return OK;
}
  • 删除操作

算法思路啊如下:

1.如果插入位置不合适,抛出异常
2.取出删除元素
3.从删除元素开始向后遍历到最后一个元素位置,分别将他们都向前移动一个位置
4.表长减1
Status ListDelete(SqList &L,int i,ElemType *e)
{
    if(L.length == 0)//异常处理
        return ERROR;
    if(i < 1 || i > L.length)//异常处理
        return ERROR;
    *e = L.data[i-1];//取出数据
    if(i < L.length)//如果删除的不是表尾数据
    {
        //将删除位置后继元素前移
        for(int j = i;j < L.length;j++)
            L.data[j-1] = L.data[j];
    }
    L.length--;
    return OK;
}
  • 求取表长
Status ListLength(SqList L)
{
	return L.length;
}
  • 查找操作
Status ListSearch(SqList L,int i)
{
	if(i < 1 || i > MAXSIZE)//异常处理
		return ERROR;
	for(int j = 0;j < L.length;j++)//遍历循环顺序表中的元素
	{
		if(L.data[j] == i)
			return (j+1);//若存在,返回数据元素在顺序表中的位置(从1开始算)
	}
	return 0;
}

三.线性表的链式存储结构

  • 结点:由指针域和数据域组成
    在这里插入图片描述
  • 线性链表:n个结点链接成一个链表
  • 单链表:链表中的每个结点都只含有一个指针域
    在这里插入图片描述
  • 头指针:链表中第一个结点存储的位置
  • 头节点:在单链表的第一个结点前附设一个结点,不存储信息,存在的意义就是为了是空链表的插入删除和非空链表一致。
    在这里插入图片描述
  • 线性表的单链表存储结构代码
typedef struct Node
{
	ElemType data;//数据域
	struct Node *next;//指针域
}Node,*LinkList;//LinkList是指向结点的指针
  • 单链表的初始化
Status InitList(LinkList &L)
{
	L = new Node;
	L->next = NULL;
	return OK;
}
  • 单链表的读取

算法思路啊如下:

1.声明一个指针p指向链表的第一个结点并初始化count从1开始
2.当count小于时,遍历链表, 让p的指针向后移动,count累加1
3.若到链表末尾p为空,则说明第i个结点不存在
4.否则查找成功,返回几点p的数据
Status GetElem(LinkList L.int i,ElemType *e)
{
	int count = 1;//count为计数器
	LinkList p;
	p = L->next;//L表示的是头结点。L->next表示的才是第一个结点
	while(p != NULL && count < i)
	{
		p = p -> next;
		++count;
	}
	if(!p || count > i)//若第i个结点不存在
		return ERROR;
	*e = p -> data;
	return OK;
}
  • 单链表的插入
    在这里插入图片描述
    算法思路啊如下:
1.声明一个指针p指向链表的第一个结点并初始化count从1开始
2.当count小于时,遍历链表, 让p的指针向后移动,count累加1
3.若到链表末尾p为空,则说明第i个结点不存在
4.否则查找成功,在系统中生成一个空结点s
5.将数据元素e赋给s->data
6.单链表的插入标准语句s->next = p->next, p->next = s
7.返回成功
Status ListInsert(LinkList &L,int i,ElemType e)
{	
	int count = 1;
	LinkList p,s;
	p = L;
	while(p != NULL && count < i)
	{
		p = p -> next;
		++count;
	}
	if(!p || j > i)
		return ERROR;
	s = new Node;
	s -> data = e;
	s -> next = p -> next;
	p -> next = s;
	return OK;
}
  • 单链表的删除操作

算法思路啊如下:

1.声明一个指针p指向链表的第一个结点并初始化count从1开始
2.当count小于时,遍历链表, 让p的指针向后移动,count累加1
3.若到链表末尾p为空,则说明第i个结点不存在
4.否则查找成功, 将欲删除的结点p->next赋值给q
单链表表的删除标准语句p->next = q->next
6.将q中的数据域赋给e,作为返回
7.释放结点q
8.返回成功
Status ListDelete(LinkList &L,int i,ElemType *e)
{
	int count = 1;
	LinkList p,s;
	p = L;
	while(p != NULL && count < i)
	{
		p = p -> next;
		++count;
	}
	if(!(p->next) || count > i)
	{
		return ERROR;
	}
	q = p->next;
	p->next = q->next;
	*e = q->data;
	delete q;
	return OK;
}
  • 单链表的整表创建
void CreateListHead(LinkList &L,int n)
{
	ElemType elem
	InitList(L);
	
	/*我们可以把单链表的插入细致分为两种,一种是头插法,一种是尾插法*/
	//头插法(并不推荐)
	LinkList p;
	for(int i = 0;i < n;i++)
	{
		std::cin>>L->data;
		p->next = L->next;
		L->next = p;
	}

	//头插法
	LinkList p,r;
	r = L;
	for(int i = 0;i < n;i++)
	{	
		p = new Node;
		std::cin>>p->data;
		r->next = p;
		r = p;
	}
	r->next = NULL;
}
  • 单链表的整表删除
Status ClearList(LinkList &L)
{
	LinkList p,q;
	p = L->next;
	while(p)
	{
		q = p->next;
		delete p;
		p = q;
	}
	L-next = NULL;
	return OK;
}

    本人也在学习中,如果有什么错误,希望大家多多指教,互相学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值