[图文并茂]C++线性表及其逻辑结构

news2024/11/25 3:44:46

1.1线性表的定义

线性表是具有相同特性的数据元素的一个有限序列
对应的逻辑结构图形:

在这里插入图片描述

从线性表的定义中可以看出它的特性:

(1)有穷性:一个线性表中的元素个数是有限的

(2)一致性:一个线性表中所有元素的性质相同,即数据类型相同

(3)序列性:各个元素的相对位置是线性的

1.2线性表的抽象数据类型描述

(如下图所示)

在这里插入图片描述

那为什么要引进这个数据结构呢?那就不得不谈谈它的作用了。

线性表的作用体现在两个方面:

a. 当一个线性表实现后,程序员加油直接使用它来存放数据,即作为存放数据的容器

b.使用线性表的基本运算来完成更复杂的运算

2.1线性表的顺序存储结构——顺序表

线性表的顺序存储结构简称为顺序表

在这里插入图片描述

(如图为线性表到顺序表的映射)

需要注意的是顺序表采用数组进行实现,但是不是任意数组可以作为一个顺序表,二者运算是不同的

​ 下图为顺序表的存储示意图

在这里插入图片描述

2.2顺序表的基本运算实现

(1)结构体SqList定义

//数据元素
typedef int ElemType;
//结构体
typedef struct
{
	ElemType data[MaxSize];
    //数据长度
	int length;
}SqList;

(2)建立顺序表

//建立顺序表
void CreateList(SqList*& L, ElemType a[], int n)
{
	int i = 0, k = 0;
	//记得一定要分配内存空间 
	L = (SqList*)malloc(sizeof(SqList));
	while (i < n)
	{
        //将a[i]存储到L中
		L->data[k] = a[i];
		k++; i++;
	}
	L->length = k;
}

(3)初始化线性表

void InitList(SqList*& L)
{
	L = (SqList*)malloc(sizeof(SqList));
	L->length = 0; //置空线性表的长度为0
}

(4)销毁线性表

void DestroyList(SqList*& L)
{
	free(L);//释放L所指的顺序表空间
}

(5)判断是否为空

bool ListEmpty(SqList* L)
{
	return(L->length == 0);
}

(6)求线性表长度

int ListLength(SqList* L)
{
	return (L->length);
}

(7)求表中某个值

bool GetElem(SqList* L, int i, ElemType& e)
{
	if (i<1 || i > L->length)
		return false;
	e = L->data[i - 1];
	return true;	//成功找到元素返回true
}

(8)按照元素值查找

int LocateElem(SqList* L,ElemType e)
{
	int i = 0;
	while (i < L->length && L->data[i] != e)
		i++;
	if (i >= L->length)
		return 0;
	else
		return i + 1;		//返回逻辑序号
}

(9)输出线性表

void DisplayList(SqList* L)
{
	for (int i = 0; i < L->length; i++)
		printf("%d", L->data[i]);
	printf("\n");
}

(10)完整代码

#include<iostream>
using namespace std;
const int MaxSize = 1005;
typedef int ElemType;
typedef struct
{
	ElemType data[MaxSize];
	int length;
}SqList;

//建立顺序表
void CreateList(SqList*& L, ElemType a[], int n)
{
	int i = 0, k = 0;
	//记得一定要分配内存空间 
	L = (SqList*)malloc(sizeof(SqList));
	while (i < n)
	{
		L->data[k] = a[i];
		k++; i++;
	}
	L->length = k;
}
//初始化线性表
void InitList(SqList*& L)
{
	L = (SqList*)malloc(sizeof(SqList));
	L->length = 0; //置空线性表的长度为0
}
void DestroyList(SqList*& L)
{
	free(L);//释放L所指的顺序表空间
}
bool ListEmpty(SqList* L)
{
	return(L->length == 0);
}

int ListLength(SqList* L)
{
	return (L->length);
}
void DisplayList(SqList* L)
{
	for (int i = 0; i < L->length; i++)
		printf("%d", L->data[i]);
	printf("\n");
}
bool GetElem(SqList* L, int i, ElemType& e)
{
	if (i<1 || i > L->length)
		return false;
	e = L->data[i - 1];
	return true;	//成功找到元素返回true
}
int LocateElem(SqList* L,ElemType e)
{
	int i = 0;
	while (i < L->length && L->data[i] != e)
		i++;
	if (i >= L->length)
		return 0;
	else
		return i + 1;		//返回逻辑序号
}
bool ListInsert(SqList*& L, int i, ElemType e)
{
	int j;
	if (i < 1 || i >L->length + 1 || L->length == MaxSize)
		return false;
	i--;
	for (j = L->length; j > i; j--)
		L->data[j] = L->data[j - 1];
	L->data[i] = e;
	L->length++;
	return true;
}
bool ListDelete(SqList*& L, int i, ElemType& e)
{
	int j;
	//特判是否符合 
	if (i < 1 || i>L->length)
		return false;
	i--;
	for (int j = i; j < L->length - 1; j++)
		L->data[j] = L->data[j + 1];
	L->length--;
	return true;
}
void delnodel(SqList*& L, ElemType x)
{
	int k = 0;
	for (int i = 0; i < L->length; i++)
		if (L->data[i] != x)
		{
			L->data[k] = L->data[i];
			k++;
		}
	L->length = k;
}

}
int main() {
	SqList* L;
	int a[10] = { 7,5,7,7,9,1,6,2,4,8 };
	CreateList(L, a, 10);

	DisplayList(L);
}

2.3线性表的链式存储结构——链表

线性表的链式存储就是链表,每个链表存储点不仅包括数据域,还有指针域。

链表示意图如下:

在这里插入图片描述

2.4 单链表算法实现

(1)数据结构声明

typedef int ElemType;
typedef struct LinkNode
{
	ElemType data;		//存放元素值
	struct LinkNode* next;	//指向后继结点

}LinkNode;

建立单链表有两种方法:头插法和尾插法

(2)头插法

//建立单链表
void CreatListF(LinkNode*& L, ElemType a[], int n)
{
	LinkNode* s;
	//创建头结点 
	L = (LinkNode*)malloc(sizeof(LinkNode));
	L->next = NULL;	//头结点指针域置NULL
	for (int i = 0; i < n; i++)
	{
		s = (LinkNode*)malloc(sizeof(LinkNode));//重新分配空间
		s->data = a[i];
		s->next = L->next;
		L->next = s;
	}
}

(3)尾插法

void CreatListR(LinkNode*& L, ElemType a[], int n)
{
	LinkNode* s, * r;
	//创建头结点
	L = (LinkNode*)malloc(sizeof(LinkNode));
	r = L;						//r始终指向尾结点,初始时指向头结点
	for (int i = 0; i < n; i++)
	{
		s = (LinkNode*)malloc(sizeof(LinkNode));//重新分配空间
		s->data = a[i];
		r->next = s;
		r = s;
	}
	//尾结点的nextt域置为NULL
	r->next = NULL;			
}

(4)初始化

void InitList(LinkNode*& L)
{
	L = (LinkNode*)malloc(sizeof(LinkNode));
	L->next = NULL;
}

(5)销毁表

void DestroyList(LinkNode*& L)
{
	LinkNode* pre = L, * p = L->next;	//pre指向p的前驱结点
	while (p != NULL)
	{
		free(pre);
		pre = p;
		p = pre->next;
	}
	free(pre);		//循环结束时p为NULL,pre指向尾结点
}

(6)输出表

void DispList(LinkNode* L)
{
	LinkNode* p = L->next;//指向头结点
	while (p!=NULL)
	{
		printf("%d", p->data);
		p = p->next;
	}
	printf("\n");
}

重点!!!

(7)链表的插入

bool ListInsert(LinkNode*& L, int i, ElemType e)
{
	int j = 0;
	LinkNode* p = L, * s;
	if (i <= 0)return false;//首结点的次序是一
	while (j < i - 1 && p != NULL)//找到第i-1个结点
	{
		j++;
		p = p->next;
	}
	if (p == NULL)
		return false;
	else
	{
		s = (LinkNode*)malloc(sizeof(LinkNode));
		//典中典
		s->data = e;
		s->next = p->next;
		p->next = s;
		return true;
	}
}

(8)删除某个元素

bool ListDelete(LinkNode*& L, int i, ElemType& e)
{
	int j = 0;
	LinkNode* p = L, * q;
	if (i <= 0)return false;//头结点是不计入其中的
	while (j < i - 1 && p != NULL)
	{
		j++;
		p = p->next;
	}		
	if (p == NULL)
		return false;
	else {
		q = p->next;
		if (q == NULL)
			return false;
		e = q->data;
		p->next = q->next;
		free(q);
		return true;
	}
}

最后介绍一下双链表

2.5双链表

(1)建立双链表

typedef int ElemType;
// 定义DlinkNode结构体
struct DlinkNode {
    int data;           // 数据域
    DlinkNode* prior;   // 前驱指针
    DlinkNode* next;    // 后继指针
};

同样的,双链表的建立也有头插法和尾插法

(2)头插法

// 定义CreateListF函数
void CreateListF(DlinkNode*& L, ElemType a[], int n)
{
    DlinkNode* s;
    L = (DlinkNode*)malloc(sizeof(DlinkNode)); // 创建头结点
    L->prior = L->next = NULL; // 先后指针域置NULL
    for (int i = 0; i < n; i++) // 循环创建数据结点
    {
        s = (DlinkNode*)malloc(sizeof(DlinkNode)); // 创建数据结点s
        s->data = a[i];
        s->next = L->next; // 将S插到头结点之后
        if (L->next != NULL)
            L->next->prior = s;
        L->next = s;
        s->prior = L;
    }
}

(3)尾插法

void CreateListR(DlinkNode*& L, ElemType a[], int n)
{
    DlinkNode* s,*r;
    L = (DlinkNode*)malloc(sizeof(DlinkNode)); // 创建头结点
    r = L;          //r始终指向尾结点,开始时指向头结点
    for (int i = 0; i < n; i++) // 循环创建数据结点
    {
        s = (DlinkNode*)malloc(sizeof(DlinkNode)); // 创建数据结点s
        s->data = a[i];
        r->next = s; s->prior = r;      //将s结点插入到r结点之后
        r = s;                          //r指向尾结点
    }
    r->next = NULL;
}

2.6总结

线性表是一种基础且重要的数据结构,常见的线性表有三种实现方式:顺序表、单链表和双链表。

​ 本文对这三种线性表的实现方式及特点做一个简要总结:

一、顺序表顺序表是将逻辑顺序上相邻的数据元素存储在物理位置上也相邻的存储单元中,通常使用数组来实现。- 特点:定位直接,通过下标操作即可快速访问任一位置的节点;实现简单。

缺点:插入删除需要移动大量元素,效率低;存储空间固定,扩容不灵活。

二、单链表单链表通过链式存储结构实现,每个节点除存储数据外,还储存下一个节点的地址信息。

-特点:存储灵活,可动态扩展,插入删除简单,效率高。-

缺点:访问任一节点需要从头结点遍历,无法直接定位

三、双链表双链表相比单链表,每个节点增加一个指向前驱节点的指针,实现双向链表。-

特点:可双向遍历链表,操作更灵活。-

缺点:每个节点存储空间略大于单链表。

综上,三种线性表各有特点,使用需根据具体场景需求选择合适的数据结构。顺序表操作简单,链表存储灵活,双链表可以双向访问。开发时需要权衡效率与实现难度,选择最优实现。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/977643.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

注册登录首选,趣味滑块验证码

前言 注册登录账户时&#xff0c;保障账户安全是首要任务&#xff01;使用趣味滑块验证码&#xff0c;既能有效防御恶意攻击&#xff0c;又能为验证过程增添一丝乐趣。让注册和登录变得更加有趣又安全&#xff01; HTML代码 <script src"https://cdn6.kgcaptcha.co…

Ubutnu python2与python3切换

python -V #查看默认版本 Python 2.7.17 python3 -V #查看电脑3的版本 Python 3.6.9 sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1 sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.6 2 #设置两个版本的…

【Linux】虚拟地址空间理解

虚拟地址空间 虚拟地址是操作系统管理内存的一种方式。**方便不同进程使用的虚拟地址彼此隔离。方便物理内存中不相邻的内存在虚拟地址上视为连续的来使用。虚拟地址和物理地址的映射是通过MMU页表进行的。虚拟内存对实际内存有保护作用。

LeetCode(力扣)17. 电话号码的字母组合Python

LeetCode17. 电话号码的字母组合 题目链接代码 题目链接 https://leetcode.cn/problems/letter-combinations-of-a-phone-number/ 代码 class Solution:def __init__(self):self.letterMap ["", # 0"", # 1"abc", # 2"def&qu…

备战9月9日C/C++青少年等级考试(1~8级)

由中国电子学会举办的《全国青少年软件编程等级考试》将于9月9日&#xff08;周六&#xff09;举行&#xff0c;你准备的怎么样了&#xff1f;我在这里列举了1~8级的历届真题及解析&#xff0c;希望能助你考试通过&#xff01;&#xff01;&#xff01; C/C编程一级 一级标准 …

Go调用jenkins api执行流水线构建与停止

用到的库&#xff1a; "github.com/bndr/gojenkins" 代码如下&#xff0c;一次到位&#xff1a; import ("context""fmt""time""github.com/bndr/gojenkins" )// 构建指定任务 func buildJob(ctx context.Context, jenkins…

CUDA 问题 ,一直头大。。。。

1.卸载cuda ubuntu系统安装/卸载cuda和cudnn_怎么删除cudnn_Zhijun.liStudio的博客-CSDN博客ubuntu系统安装/卸载cuda和cudnn_怎么删除cudnnhttps://blog.csdn.net/weixin_45921929/article/details/128849198?ops_request_misc%257B%2522request%255Fid%2522%253A%252216939…

机器学习算法系列————决策树(二)

1.什么是决策树 用于解决分类问题的一种算法。 左边是属性&#xff0c;右边是标签。 属性选择时用什么度量&#xff0c;分别是信息熵和基尼系数。 这里能够做出来特征的区分。 下图为基尼系数为例进行计算。 下面两张图是对婚姻和年收入的详细计算过程&#xff08;为GINI系…

Hive_Hive统计指令analyze table和 describe table

之前在公司内部经常会看到表的元信息的一些统计信息&#xff0c;当时非常好奇是如何做实现的。 现在发现这些信息主要是基于 analyze table 去做统计的&#xff0c;分享给大家 实现的效果某一个表中每个列的空值数量&#xff0c;重复值数量等&#xff0c;平均长度 具体的指令…

Freecycle出现大规模数据泄露事件,影响700万用户

Freecycle是一个致力于交换二手物品的在线论坛&#xff0c;拥有来自全球5300多个地方城镇的近1100万名用户。该论坛近日发生了大规模数据泄露事件&#xff0c;700 多万用户受到影响。 该组织称是在上周三&#xff08;8月30日&#xff09;发现这一漏洞的&#xff0c;而在此之前…

Nand Flash的特性及烧录问题

目录 前言 一 Nand flash的特性 1 存储结构 2 OOB区域 3 位翻转 4 坏块及ECC 二 Nand系统裸片量产烧录 1 坏块处理策略 2 分区(Partition) 3 纠错码(Error Correction Codes&#xff0c;ECC) 4. 擦除坏块 &#x1f388;个人主页&#x1f388;&#xff1a;linux_嵌入式…

LeetCode(力扣)39. 组合总和Python

LeetCode20. 有效的括号 题目链接代码 题目链接 https://leetcode.cn/problems/combination-sum/description/ 代码 class Solution:def backtracking(self, candidates, stratindex, path, target, result, total):if total > target:returnif total target:result.ap…

php://filter协议在任意文件读取漏洞(附例题)

php://filter php://fiter 中文叫 元器封装&#xff0c;咱也不知道为什么这么翻译&#xff0c;目前我的理解是可以通过这个玩意对上面提到的php IO流进行处理&#xff0c;及现在可以对php的 IO流进行一定操作。 过滤器&#xff1a;及通过php://filter 对php 的IO流进行的具体…

React中父子组件参数传递讲解

文章目录 结合案例&#xff1a;github搜索案例1.父容器代码2.搜索Search子模块代码3.展示Lisi子模块代码 父子参数传递分析1.子(Search)传父(App)2.父(App)传子(List) 结合案例&#xff1a;github搜索案例 案例结果展示如下图 1.父容器代码 import React, { Component } fr…

经典浏览器の介绍

经典浏览器&#xff0c;这里给你介绍几款常见的浏览器&#xff1a; Google Chrome&#xff1a;Google Chrome是由Google开发的一款流行的浏览器。它以出色的性能和速度而闻名&#xff0c;能够快速加载网页。Chrome还支持大量的扩展和应用程序&#xff0c;可以个性化定制浏览器功…

二进制安全虚拟机Protostar靶场(2)基础知识讲解,栈溢出覆盖变量 Stack One,Stack Two

前言 Protostar靶场的安装和一些二进制安全的基础介绍在前文已经介绍过了&#xff0c;这里是文章链接 https://blog.csdn.net/qq_45894840/article/details/129490504?spm1001.2014.3001.5501什么是缓冲区溢出 当系统向缓冲区写入的数据多于它可以容纳的数据时&#xff0c;…

算法通关村第十九关——最小路径和

LeetCode64. 给定一个包含非负整数的 m n 网格 grid,请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 输入&#xff1a;grid[[1,3,1],[1,5,1],[4,2,1]] 输出&#xff1a;7 解释&#xff1a;因为路径1→3→1→1→1的总和最小。 public int minPath…

交叉熵损失函数(Cross-Entropy Loss)

交叉熵损失函数&#xff08;Cross-Entropy Loss&#xff09;是在深度学习中常用的损失函数之一&#xff0c;它适用于分类问题。交叉熵损失函数的作用是衡量预测结果与真实标签之间的差距&#xff0c;从而用于模型的优化。 越接近真实标签&#xff0c;损失越小。在交叉熵损失函…

时序预测 | MATLAB实现LSSVM最小二乘支持向量机时间序列预测未来

时序预测 | MATLAB实现LSSVM最小二乘支持向量机时间序列预测未来 目录 时序预测 | MATLAB实现LSSVM最小二乘支持向量机时间序列预测未来预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现LSSVM时间序列预测未来(最小二乘支持向量机)&#xff1b; 2.运行环境Mat…

VIRTIO-BLK代码分析(1)VIRTIO设备的模拟

VIRTIO设备的模拟是由QEMU实现的&#xff0c;它的具现化由函数virtio_device_class_init()实现。 VIRTIO PCI设备包含common/isr/device/notify BAR&#xff0c;QEMU模拟并注册这几个BAR MR&#xff0c;这里同时也注册read/write函数。 VIRTIO-BLK设备的具现化由函数virtio_blk…