线性表之(定长/动态)顺序表基本操作(C语言实现)

目录

1.线性表的类型定义

2.定长顺序表的实现和表示

3.动态顺序表的实现和表示


1.线性表的类型定义

       在数据结构中线性表是最常用且最好用的一种结构,线性结构的特点是在数据元素的非空有限集合中,除第一个元素无直接前驱、最后一个元素无直接后继外,集合中其余每个数据元素均有唯一的直接前驱和直接后继。

     通俗的理解直接前驱和直接后继:在食堂排队打饭时,除队头和队尾两人外,一个人的前面紧挨那个人就成为直接前驱,后面紧挨着的人叫直接后继,排在队头第一个的人称为第一个元素,队尾最后一个人称为最后一个元素,显然第一个人前没有人故无直接前驱,同理最后一个人后无直接后继。

    线性表(Linear List)描述:线性表是n个类型相同数据元素的有限序列,对n>0,除第一个元素无直接前驱,最后一个元素无直接后继外,其余的每个数据元素只有一个直接前驱和一个直接后继,数据元素之间具有一对一的关系

  线性表的基本操作:

//初始化操作
void InitSQList(PSQList ps);

//插入数据,在ps顺序表的pos位置插入val
bool Insert(PSQList ps, int pos, int val);

//判空
bool Isempty(PSQList ps);

//判满
bool IsFull(PSQList ps);

//在ps中查找第一个val值,找到则返回下标,没有找到返回-1
int Search(PSQList ps, int key);

//删除pos位置的值
bool DelPos(PSQList ps, int pos);

//删除第一个val的值
bool Delval(PSQList ps, int val);

//返回key的前驱下标,如果不存在返回-1
int GetPrio(PSQList ps, int key);

//返回key的 后继下标 ,如果不存在返回-1
int GetNext(PSQList ps, int key);

//展示顺序表
void Show(PSQList ps);

//清空顺序表
void Clear(PSQList ps);

//销毁整个内存
void Destory(PSQList ps);



2.定长顺序表的表示和实现

      线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素,使得线性表中在逻辑结构上相邻的数据元素存储在物理存储上也相邻。可将顺序表归纳为:关系线性化,结点顺序存

  定长顺序表的顺序存储结构:

#include<stdio.h>
//定长顺序表
typedef struct SQList
{
	int len;//长度
	int elem[10];
}SQList,*PSQList;

   注意:在插入操作中,需要将待插入位置后的元素移动一个位置,为将要插入的元素空出一个位置,再将元素插入到顺序表中,同理删除操作,将元素删除后,后面的所有元素向前移动一个位置。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<assert.h>
#include"顺序表.h"

void InitSQList(PSQList ps)
{
	assert(ps != NULL);
	if (ps == NULL)
	{
		return;
	}
	ps->len = 0;
}

bool Insert(PSQList ps, int pos, int val)
{
	assert(ps != NULL);
	if (ps == NULL)
		return false;
	if ((pos > ps->len) || pos < 0||IsFull(ps))
		return false;
	for (int i = ps->len-1; i >= pos; i--)
	{
		ps->elem[i + 1] = ps->elem[i];
	}
	ps->elem[pos - 1] = val;
	ps->len++;
	return true;
}

static bool IsFull(PSQList ps)//判满函数为内部函数,故声明为static,不可在外使用。
{
	return ps->len == 10;
}

bool Isempty(PSQList ps)
{
	return ps->len == 0;
}

int Search(PSQList ps, int key)
{
	assert(ps != NULL);
	if (ps == NULL)
		return false;
	for (int i = 0; i < ps->len - 1; i++)
	{
		if (ps->elem[i] == key)
			return i;
	}
	return -1;
}

bool DelPos(PSQList ps, int pos) 
{
	assert(ps != NULL);
	if (ps == NULL)
		return  false;
	if (pos < 0 || pos >= ps->len)
	{
		return false;
	}
	for (int i = pos - 1; i < ps->len - 1; i++)
	{
		ps->elem[i] = ps->elem[i + 1];
	}
	ps->len--;
	return true;
}

bool Delval(PSQList ps, int val)
{
	assert(ps != NULL);
	if (ps == NULL)
		return false;
	int i = Search(ps, val);
	if (i < 0)
		return false;
	return DelPos(ps, i);
}

int GetPrio(PSQList ps, int key)
{
	int i = Search(ps, key);
	if (i <= 0)
	{
		return -1;
	}
	return i - 1;
}

int GetNext(PSQList ps, int key)
{
	int i = Search(ps, key);
	if (i < 0 || i == ps->len - 1)
	{
		return -1;
	}

	return i + 1;
}

void Show(PSQList ps)
{
	assert(ps != NULL);
	if (ps == NULL)
		return;

	for (int i = 0; i < ps->len - 1; i++)
	{
		printf("%d  ", ps->elem[i]);
	}
	printf("\n");
}

int main()
{
	SQList sq;
	//printf("%d", sizeof(sq));
	InitSQList(&sq);

	for (int i = 0; i < 10; i++)
	{
		Insert(&sq, i, i);//在顺序表中插入元素
	}
	Show(&sq);
	
	Delval(&sq, 5);
	Show(&sq);
	printf("3的前驱下标为:%d\n", GetPrio(&sq, 9));
	printf("3的后继下标为:%d\n", GetNext(&sq, 9));

	return 0;
}

3.动态顺序表的实现和表示

  线性表的动态分配顺序存储结构:

#define INIT_SIZE  10
//可扩容的顺序表 
typedef struct DSQList
{
	int* elem;//动态内存的地址
	int length;//有效数据的个数
	int listsize;//总容量
}DSQList, * DPSQList;
#include "动态顺序表.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>

//初始化
void InitSqlist(DPSQList ps)
{
	assert(ps != NULL);
	if (ps == NULL)
	{
		return;
	}
	ps->elem = (int*)malloc(sizeof(int) * INIT_SIZE);
	assert(ps->elem != NULL);
	ps->length = 0;
	ps->listsize = INIT_SIZE;
}

static  bool IsFull(DPSQList ps)
{
	return ps->length == ps->listsize;
}

static bool Inc(DPSQList ps)
{
	ps->elem = (int*)realloc(ps->elem, ps->listsize * 2 * sizeof(int));
	assert(ps->elem != NULL);
	ps->listsize *= 2;
	//ps->length;//不变
	return true;
}

//插入数据,在ps顺序表的pos位置插入val
bool Insert(DPSQList ps, int pos, int val)
{
	assert(ps != NULL);
	if (ps == NULL)
	{
		return false;
	}
	if (pos<0 || pos>ps->length)
	{
		return false;
	}
	if (IsFull(ps))
	{
		Inc(ps);
	}
	//把数据往后移动
	for (int i = ps->length - 1; i >= pos; i--)
	{
		ps->elem[i + 1] = ps->elem[i];
	}
	//插入数据
	ps->elem[pos] = val;
	//有效数据个数++
	ps->length++;

	return true;
}

//判空
bool IsEmpty(DPSQList ps)
{
	return ps->length == 0;
}

//在ps中查找第一个val.找到返回下标,没有找到返回-1
int Search(DPSQList ps, int key)
{
	for (int i = 0; i < ps->length; i++)
	{
		if (key == ps->elem[i])
		{
			return i;
		}
	}

	return -1;
}

//删除pos位置的值
bool DelPos(DPSQList ps, int pos)
{
	assert(ps != NULL);
	if (ps == NULL)
	{
		return false;
	}
	if (pos < 0 || pos >= ps->length)
	{
		return false;
	}

	for (int i = pos; i < ps->length - 1; i++)
	{
		ps->elem[i] = ps->elem[i + 1];
	}
	//有效数据--
	ps->length--;
	return true;
}

//删除第一个val的值
bool DelVal(DPSQList ps, int val)
{
	int i = Search(ps, val);
	if (i < 0)
	{
		return false;
	}

	return DelPos(ps, i);
}

//返回key的前驱下标,如果不存在返回-1
int GetPrio(DPSQList ps, int key)
{
	int i = Search(ps, key);
	if (i <= 0)
	{
		return -1;
	}
	return i - 1;
}

//返回key的后继下标,如果不存在返回-1
int GetNext(DPSQList ps, int key)
{
	int i = Search(ps, key);
	if (i < 0 || i == ps->length - 1)
	{
		return -1;
	}

	return i + 1;
}

//输出
void Show(DPSQList ps)
{
	for (int i = 0; i < ps->length; i++)
	{
		printf("%d ", ps->elem[i]);
	}
	printf("\n");
}

//清空数据
void Clear(DPSQList ps)
{
	ps->length = 0;
}

//销毁整个内存
void Destroy(DPSQList ps)
{
	free(ps->elem);//1
	ps->elem = NULL;//2
	ps->length = 0;//3
	ps->listsize = 0;//4
	//ps = NULL;//5无效的代码
}

线性表顺序表示的优点:

  ①无需为表示结点间的逻辑关系而增加额外的存储空间(因为逻辑上相邻的元素其存储物理位置也是相邻的)。

  ②可方便地随机存取表中的任意元素。

线性表顺序表示的缺点:

  ①插入和删除运算不方便,除表尾的位置外,在表的其他位置上进行插入或删除操作都必须移动大量的结点,其效率较低。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十七^O^

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值