数据结构———线性表(考研:第二章)


知识框架:
在这里插入图片描述

一、线性表的基本概念

1.线性表的定义
线性表是具有相同数据类型的n个数据元素的有限序列,其中n为表长。

//静态分配存储空间
#define MaxSize 10
typedef struct {
	int data[MaxSize];
	int length;
}SqList;
//动态分配存储空间
typedef struct {
	int *data;
	int MaxSize, length;
}SeqList;

2.线性表的基本操作
InitList(&L):初始化表。构造一个空的线性表。

//静态初始化
void initList(SqList & L) {
	for (int  i = 0; i <MaxSize; i++)
		L.data[i] = 0;
	L.length = 0;
}
//动态分配内存空间初始化
void initList(SeqList& L) {
	L.data = (int*)malloc(sizeof(int) * InitSize);
	L.length = 0;
	L.MaxSize = InitSize;
}

Length(L):求表长。返回线性表L的长度,即L中数据元素的个数
LocateElem(L,e):按值查找操作。在表L中查找具有给定关键值的元素

int LocatElem(SqList L,int e) {
	for (int i = 0; i < L.length; i++)
		if (L.data[i]==e)
			return i + 1;
	return 0;
}

GetElem(L,i):按位查找操作。获取表L中第i个位置的元素的值

int GetElem(SqList L, int i) {
	return L.data[i - 1];
}

ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e

bool ListInsert(SqList &L, int i, int e) {
	if (i<1 || i>L.length + 1) {
		printf("该位置不可以插入元素\n");
		return false;
	}
		
	if (L.length >= MaxSize) {
		printf("存储空间已满,不可以再插入元素\n");
		return false;
	}

	for (int j=L.length;j>=i; i--)
		L.data[j] = L.data[j - 1];
	L.data[i - 1] = e;
	L.length++;
	return true;
}

ListDelete(&L,i,&e):删除操作。删除表中第i个位置的元素,并用e返回删除元素的值

bool ListDelete(SqList &L,int i,int & e) {
	if (i<1 || i>L.length) {
		printf("该位置没有元素可以删除\n");
		return false;
	}
	e = L.data[i-1];
	for (int j = i; j < L.length; i++)
		L.data[j-1] = L.data[j];
	L.length--;
	return true;
}

PrintList(L):输出操作。按前后顺序输出线性表L的所有元素值。
Empty(L):判空操作。若L为空表,则返回true,否则返回false
DestroyList(&L):销毁操作。销毁线性表,并释放线性表L所占用的内存空间。

二、线性表的实现

1.顺序存储

顺序表的定义:线性表的顺序存储又称顺序表。 顺序表的特点是表中元素的逻辑顺序与物理顺序相同。

顺序表上基本操作的实现:
(1)插入操作

//插入函数 位置i插入数据 i及之后元素后移  1=<i<=length+1 
bool InsertList(SqList& L, int i, int e)
{
	if (i<1 || i>L.length + 1) //判断位置是否有效
	{
		printf("位置无效!!!\n");
		return false;
	}
	if (L.length >= MaxSize)//判断存储空间是否已满
	{
		printf("当前存储空间已满!!!\n");
		return false;
	}
	for (int j = L.length; j >= i; j--)//位置i及之后元素后移
	{
		L.data[j] = L.data[j - 1];
	}
	L.data[i - 1] = e;
	L.length++;
	for (int i = 0; i < L.length; i++)
		cout << L.data[i] << " ";
	return true;
}

(2)删除操作

//删除函数 删除位置i的元素 i之后的元素依次前移
bool  ListDelete(SqList& L, int i)
{
	if (i<1 || i>L.length)
	{
		printf("位置无效!!!\n");
		return false;
	}
	for (int j = i; j <= L.length - 1; j++)//位置i之后元素依次前移覆盖
	{
		L.data[j - 1] = L.data[j];
	}
	L.length--;
	for (int i = 0; i < L.length; i++)
		cout << L.data[i] << " ";
	return true;
}

(3)按值查找(顺序查找【注:也可以使用其他的查找方法】)

//查找函数 按位置从小到大查找第一个值等于e的元素 并返回位置
int LocateElem(SqList L, int e)
{
	for (int i = 0; i < L.length; i++)//从低位置查找
		if (L.data[i] == e)
			return i + 1;
	return 0;
}

总代码:

#include<iostream>
#include <malloc.h>
#define MaxSize 50

using namespace std;

typedef struct {
	int data[MaxSize];
	int length;
}SqList;


int InitList(SqList& L)
{
	memset(L.data,0,sizeof(L));//初始化数据为0
	L.length = 0;                //初始化长度为0
	return 0;
}
//创建顺序表函数 初始化前n个数据
bool CreateList(SqList& L, int n)
{
	if (n<0 || n>MaxSize)false;//n非法
	for (int i = 0; i< n; i++)
	{
		cin >> L.data[i];
		L.length++;
	}
	cout << "顺序表如下所示:" << endl;
	for (int i = 0; i < n; i++)
		cout<<L.data[i]<<" ";
	return true;  
}
//插入函数 位置i插入数据 i及之后元素后移  1=<i<=length+1 
bool InsertList(SqList& L, int i, int e)
{
	if (i<1 || i>L.length + 1) //判断位置是否有效
	{
		printf("位置无效!!!\n");
		return false;
	}
	if (L.length >= MaxSize)//判断存储空间是否已满
	{
		printf("当前存储空间已满!!!\n");
		return false;
	}
	for (int j = L.length; j >= i; j--)//位置i及之后元素后移
	{
		L.data[j] = L.data[j - 1];
	}
	L.data[i - 1] = e;
	L.length++;
	for (int i = 0; i < L.length; i++)
		cout << L.data[i] << " ";
	return true;
}
//删除函数 删除位置i的元素 i之后的元素依次前移
bool  ListDelete(SqList& L, int i)
{
	if (i<1 || i>L.length)
	{
		printf("位置无效!!!\n");
		return false;
	}
	for (int j = i; j <= L.length - 1; j++)//位置i之后元素依次前移覆盖
	{
		L.data[j - 1] = L.data[j];
	}
	L.length--;
	for (int i = 0; i < L.length; i++)
		cout << L.data[i] << " ";
	return true;
}
//查找函数 按位置从小到大查找第一个值等于e的元素 并返回位置
int LocateElem(SqList L, int e)
{
	for (int i = 0; i < L.length; i++)//从低位置查找
		if (L.data[i] == e)
			return i + 1;
	return 0;
}

int main() {
	SqList L;	//定义顺序表L
	InitList(L);	//初始化顺序表

	int n;
	cout << "请输入数组的大小n:" << endl;
	cin >> n;
	cout << "请输入数组的元素:" << endl;
	CreateList(L,n);	//创造顺序表,即给顺序表中的元素赋值
	cout << endl;

	cout<< "插入操作:请输入位置i和数值e" <<endl;
	int i, e;
	cin >>i>>e;
	InsertList(L, i, e);

	cout << endl;
	cout << "删除操作:请输入你要删除的位置i:" << endl;
	int i1;
	cin >> i1;
	ListDelete(L, i1);

	cout << endl;
	cout << "查找操作:请输入你要查找的元素值e:" << endl;
	int e1;
	cin >> e1;
	cout<<LocateElem(L, e1)<<endl;
	return 0;
}

截图:
在这里插入图片描述

2.链式存储

(1)单链表

线性表的链式存储又称为单链表。
它是通过一组任意的存储单元来存储线性表中的数据元素。为了建立数据元素之间的线性关系,对每个链表结点,除存放元素自身的信息外,还需要存放一个指向其后继的指针。

引入头结点的两个优点:
①:由于第一个数据结点的位置被存放在头结点的指针域中,因此在链表的第一个位置上的操作和在表的其他位置上的操作一致,无需进行特殊处理
②:无论链表是否为空,其头指针都指向头结点的非空指针(空表中头结点的指针域为空),因此空表和非空表的处理也得到了统一。

1.采用头插法建立单链表:

//头插法建立单链表
LinkList List_HeadInsert(LinkList& L) {
	int x;
	L = (LinkList)malloc(sizeof(LNode));
	L->next = NULL;
	LNode* s;						
	scanf("%d", &x);
	while (x != 9999) {
		s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		s->next = L->next;
		L->next = s;
		scanf("%d", &x);
	}
	return L;
}

2.采用尾插法建立单链表:

//尾插法建立单链表
LinkList List_TailInsert(LinkList& L) {
	int x;
	L = (LinkList)malloc(sizeof(LNode));	
	LNode* s, * r = L;						//r为表尾指针
	scanf("%d", &x);
	while (x != 9999) {
		s= (LNode *)malloc(sizeof(LNode));
		s->data = x;
		r->next = s;
		r = s;
		scanf("%d", &x);
	}
	r->next = NULL;
	return L;
}

3.按序号查找结点值:

//按位查找(不带头结点)
LNode* GetElem(LinkList L, int i) {
	LNode* p = L->next;
	int j = 1;
	if (i == 0)
		return L;
	if (i < 1)
		return NULL;
	while (p!=NULL||j<i)
	{
		p = p->next;
		j++;
	}
	return p;
}

//按位查找(带头结点)
LNode* GetElem(LinkList L, int i) {
	if (i < 0)
		return NULL;
	LNode* p = L;
	int j = 0;
	while (p != NULL || j < i)
	{
		p = p->next;
		j++;
	}
	return p;
}

4.按值查找表结点

//按值查找
LNode* LocatElem(LinkList L,int e) {
	LNode* p = L->next;
	while (p!=NULL&& p->data!=e)
		p = p->next;
	return p;
}

5.插入结点操作

//插入操作(不带头结点)
bool ListInsert2(LinkList& L, int i, int e) {
	if (i < 1)
		return false;
	if (i==1)
	{
		LNode *s = (LNode*)malloc(sizeof(LNode));
		s->data = e;
		s->next = L;
		L = s;
		return true;
	}
	LNode* p = L;
	int j = 1;
	while (p != NULL || j < i - 1)
	{
		p = p->next;
		j++;
	}
	if (p == NULL)
		return false;
	LNode* s = (LNode*)malloc(sizeof(LNode));
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;
}

//尾插入(由于是在结点的后面插入元素,所以不需要考虑是否有头结点)
bool InsertNextNode(LNode* p, int e) {
	if (p == NULL)
		return false;
	LNode* s = (LNode*)malloc(sizeof(LNode));
	if (s == NULL)
		return false;//内存分配失败
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;
}

//头插入(有头结点 虚假的前插入)
bool InsertPriorNode(LNode *p, int e) {
	if (p == NULL)
		return false;
	LNode *s = (LNode*)malloc(sizeof(LNode));
	if (s == NULL)
		return false;//内存分配失败
	s->next = p->next;
	p->next = s;
	s->data = p->data;
	p->data = e;
	return true;
}

6.删除结点操作

//删除操作
//带头结点删除
bool ListDelete1(LinkList &L,int i, int e) {
	if (i<1)
		return false;
	LNode *p = L;
	int j = 0;
	while (p == NULL || j < i - 1) {
		p = p->next;
		j++;
	}
	if (p == NULL||p->next==NULL)
		return false;
	LNode* q = p->next;
	e = q->data;
	p->next = q->next->next;
	free(q);
	
	return true;
}

//不带头结点删除
bool ListDelete2(LinkList &L, int i, int e) {
	if (i < 1)
		return false;
	LNode* p = L;
	int j = 0;
	while (p == NULL || j < i - 1) {
		p = p->next;
		j++;
	}
	if (p == NULL || p->next == NULL)
		return false;
	if (i == 1)
		L = L->next;
	return true;
}

7.求表长操作

(2)双链表

单链表结点中只有一个指向其后继的指针,使得单链表只能从头结点以此顺序往后遍历。
双链表有两个指针prior和next,分别指向其前驱结点和后继结点

1.双链表的插入操作

2.双链表的删除操作

(3)循环链表

1.循环单链表 循环单链表与单链表的区别是:表中的最后一个结点的指针不是NULL,而该为指向头结点,从而整个链表形成一个环。
2.循环双链表 循环双链表与双链表同循环单链表与单链表的关系

(4)静态链表(借助数组实现)

静态链表借助数组来描述线性表的链式存储结构,结点也有数据域data和指针域next,与其他链表中的指针不同的是,这里的指针是结点的相对地址(数组的下标),又称游标。和顺序表一样,静态链表也要预先分配好一块连续的内存空间。

//静态链表
#define MaxSize 10
typedef struct
{
	int data;
	int next;
}SLinkList[MaxSize];


void main() {
	LinkList L;
	InitList1(L);
}

需要数据结构、计算机网络、操作系统、计算机组成原理、c语言等等学习视频的!!!!!
微信公众号:小小小灵通 回复:王道 获取王道的教学视频、笔记、文档等提升课。(免费获取)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

名称是:小小小灵通

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

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

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

打赏作者

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

抵扣说明:

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

余额充值