顺序表的基本操作(初始化,增,删,查,改等等)

news2024/11/25 14:26:54

1.线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使
用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,
线性表在物理上存储时,通常以数组和链式结构的形式存储。

2.顺序表概念及结构

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存
储。在数组上完成数据的增删查改。

 顺序表一般可以分为:
1. 静态顺序表:使用定长数组存储元素。

2. 动态顺序表:使用动态开辟的数组存储。
 

  静态顺序表的定义

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#define N 1000
typedef int SLdatatype;
typedef struct SedList
{
	int a[N];
	int sz;
}SL;

但静态顺序表是有缺陷的如果N给小了不够用,N给大了浪费空间。所以不推荐用静态顺序表。

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空
间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间
大小,所以下面我们实现动态顺序表。

动态顺序表的定义

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLdatatype;
typedef struct SedList
{
	SLdatatype* a;//用指针指向动态开辟的数组
	int sz;//空间大小==有效数据个数
	int capacity;//容量
}SL;

动态顺序表的好处:当顺序表有效空间满了以后可以用capacity扩容空间继续存放有效数据。

顺序表的初始化

void SLInit(SL* ps)
{
	assert(ps);
	ps->a = (SLdatatype*)malloc(sizeof(SLdatatype)*4);
	if (ps->a == NULL)
	{
		perror("malloc fail");
		return;
	}
	ps->sz = 0;
	ps->capacity = 4;
}

我们在初始化的时候也可以直接把ps->a=NULL;ps->sz=0;ps->capacity=0; 但不推荐这样,最好在初始化的时候开辟一点空间,最重要的是记得用指针接受并在test.c文件&传值,要不然不能改变结构体的内容,因为不传值相当于的实参的临时拷贝,不会改变顺序表的内容。

顺序表的销毁

void SLDestroy(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->sz = 0;
}

因为在初始化的时候ps->a我们是用malloc在堆上开辟出来的,所以我们要自己free掉这个指针 ,再把指针置为NULL避免野指针的问题,也可以不置空因为free以后可能不会有人使用这个指针指向别的空间,但最好是置空一下。

 顺序表的尾插

void SLPushBack(SL* ps, SLdatatype x)
{
	ps->a[ps->sz] = x;
	ps->sz++;

}

尾插很简单只需找到尾部然后插入,再ps->sz++即可; 但如果上图插入一个数据以后sz空间就满了,再插入数据就越界了,所以我们在插入之前要检查空间,如果满了就要扩容,然后再插入空间才不会发生越界。

顺序表的检查并扩容

void SLCheckcapacity(SL* ps)
{
	if (ps->sz == ps->capacity)
	{
		SLdatatype* tmp = (SLdatatype*)realloc(ps->a, sizeof(SLdatatype)*ps->capacity * 2);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps->a = tmp;
		ps->capacity *= 2;
	}
}

顺序表的正确尾插

void SLPushBack(SL* ps, SLdatatype x)
{
	SLCheckcapacity(ps);
	ps->a[ps->sz] = x;
	ps->sz++;

}

增加检查函数以后想插入几个就插入几个,不会发生越界问题。 

顺序表的打印

void SLprint(SL* ps)
{
	int i = 0;
	for (i = 0; i < ps->sz; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");

}

顺序表的打印就没啥说的,遍历一遍打印即可。

顺序表的头插

void SLPushFront(SL* ps, SLdatatype x)
{
	SLCheckcapacity(ps);
	int end = ps->sz - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->sz++;


}

 

头插如果我们从前往后挪会覆盖数据,所以我们要从后往前挪动数据。 

一定要记得end位置是ps->sz-1,而不是ps->sz;然后挪动即可。

顺序表的尾删

void SLPopBack(SL* ps)
{
	ps->a[ps->sz];
	ps->sz--;

}

千万不要写成ps->a[ps->sz-1]=0;然后ps->sz--;尾删的时候初始化成0没有意义,因为如果它本身的值就是0你改成0有什么意义,所以直接把空间ps->sz--即可。 但这个代码存在一定的问题,因为一直尾删ps->sz--如果一直--下去,它会出现越界,会出现ps->sz=-1的位置存放有效数据,相当于越界,当一直尾删到ps->sz==0的位置再减减ps->sz==-1,然后再进行尾插的时候就会出现越界,

ps->a[ps->sz]=x,就会变成ps->a[-1]=有效数据,就会越界所以我们要断言一下。

void SLPopBack(SL* ps)
{
	//暴力的检查
	assert(ps->sz > 0);
	//温柔的检查
	//if (ps->sz == 0)
	//{
	//	printf("链表为空,不能删除!");
	//	return;
	//}
	ps->a[ps->sz];
	ps->sz--;

}

两种方式都可以检查,但推荐使用断言,断言会直接报错并且告诉你在第几行出问题。 

顺序表的头删

void SLPopFront(SL* ps)
{
第一种方法
	assert(ps->sz > 0);
	int start = 0;
	while (start < ps->sz-1)
	{
		ps->a[start] = ps->a[start + 1];
		start++;
	}
	ps->sz--;
 

第二种方法
assert(ps->sz > 0);
     int start = 1;
	while (start < ps->sz)
	{
		ps->a[start-1] = ps->a[start];
		start++;
	}
	ps->sz--;


}

头删也要断言一下防止越界。注意这里的条件是ps->sz-1,不是ps->sz,如果你start是指向第一个位置可以写成ps->sz。

顺序表的插入


void SLInsert(SL* ps, int pos, SLdatatype x)
{
   assert(0 <= pos && pos <= ps->sz);
	SLCheckcapacity(ps);
	int end = ps->sz - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[pos] = x;
	ps->sz++;
}

只要插入数据就要检查空间大小,然后pos位置要插入就要挪动数据,从后往前挪,大于pos的位置,然后把pos的位置插入要插入的有效数据,再把空间ps->sz++即可。 还有断言pos,因为在我们插入数据的时候,可能会超过size本身的容量就插入,比如有4个空间,别人在空间以外20的位置插入了30,就会发生越界行为,所以我们要断言一下0<=pos&&pos<=ps->size即可。

 当我们把Insert函数写完以后可以复用在头插和尾插函数当中。

void SLPushBack(SL* ps, SLdatatype x)
{
	//SLCheckcapacity(ps);
	//ps->a[ps->sz] = x;
	//ps->sz++;
	SLInsert(ps, ps->sz, x);

}

void SLPushFront(SL* ps, SLdatatype x)
{
	/*SLCheckcapacity(ps);
	int end = ps->sz - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->sz++;*/
	SLInsert(ps, 0, x);


}

简直妙妙米奇屋!

顺序表的删除

void SLErase(SL* ps, int pos)
{
	assert(0 <= pos && pos < ps->sz);
	//assert(ps->sz > 0);
	int start = pos+1;
	while (start <ps->sz)
	{
		ps->a[start - 1] = ps->a[start];
		start++;
	}
	ps->sz--;


}

第二句断言可有可无,因为在第一句断言就已经判断了 pos大于0,sz就一定不为空。最重要的是pos<ps->sz,不是<=ps->sz,要不然会越界。

写完Erase函数也能复用头删和尾删

void SLPopBack(SL* ps)
{
	//暴力的检查
	//assert(ps->sz > 0);
	温柔的检查
	if (ps->sz == 0)
	{
		printf("链表为空,不能删除!");
		return;
	}
	//ps->a[ps->sz];
	//ps->sz--;
	SLErase(ps, ps->sz - 1);

}

void SLPopFront(SL* ps)
{
	//assert(ps->sz > 0);
	/*int start = 0;
	while (start < ps->sz-1)
	{
		ps->a[start] = ps->a[start + 1];
		start++;
	}
	ps->sz--;*/

	/*int start = 1;
	while (start < ps->sz)
	{
		ps->a[start-1] = ps->a[start];
		start++;
	}
	ps->sz--;*/
	SLErase(ps, 0);

}

 香死了!

顺序表的查找下标返回下标

int SLFind(SL* ps, SLdatatype x)
{
	int i = 0;
	for (i = 0; i < ps->sz; i++)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}
	return -1;

}

 顺序表的修改

void SLModify(SL* ps, int pos, SLdatatype x)
{
	assert(0 <= pos && pos < ps->sz);
	ps->a[pos] = x;
}

顺序表完整代码展示

头文件

SedList.h
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLdatatype;
typedef struct SedList
{
	SLdatatype* a;//用指针指向动态开辟的数组
	int sz;//空间大小==有效数据个数
	int capacity;//容量
}SL;


void SLInit(SL* ps);//初始化
void SLprint(SL* ps);//打印
void SLDestroy(SL* ps);//销毁


void SLPushBack(SL* ps, SLdatatype x);//尾插
void SLPushFront(SL* ps, SLdatatype x);//头插
void SLPopBack(SL* ps);//尾删
void SLPopFront(SL* ps);//头删

void SLInsert(SL* ps, int pos, SLdatatype x);//插入
void SLErase(SL* ps, int pos);//删除

int SLFind(SL* ps, SLdatatype x);//找到下标返回下标
void SLModify(SL* ps,int pos,SLdatatype x);//修改

 SedList.c

#include"SedList.h"
void SLInit(SL* ps)
{
	assert(ps);
	ps->a = (SLdatatype*)malloc(sizeof(SLdatatype)*4);
	if (ps->a == NULL)
	{
		perror("malloc fail");
		return;
	}
	ps->sz = 0;
	ps->capacity = 4;
}

void SLDestroy(SL* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->sz = 0;


}
void SLprint(SL* ps)
{
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->sz; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");

}
void SLCheckcapacity(SL* ps)
{
	assert(ps);
	if (ps->sz == ps->capacity)
	{
		SLdatatype* tmp = (SLdatatype*)realloc(ps->a, sizeof(SLdatatype)*ps->capacity * 2);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps->a = tmp;
		ps->capacity *= 2;
	}
}
void SLPushBack(SL* ps, SLdatatype x)
{
	assert(ps);
	//SLCheckcapacity(ps);
	//ps->a[ps->sz] = x;
	//ps->sz++;
	SLInsert(ps, ps->sz, x);

}
void SLPushFront(SL* ps, SLdatatype x)
{
	assert(ps);
	/*SLCheckcapacity(ps);
	int end = ps->sz - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->sz++;*/
	SLInsert(ps, 0, x);


}
void SLPopBack(SL* ps)
{
	assert(ps);
	//暴力的检查
	//assert(ps->sz > 0);
	温柔的检查
	if (ps->sz == 0)
	{
		printf("链表为空,不能删除!");
		return;
	}
	//ps->a[ps->sz];
	//ps->sz--;
	SLErase(ps, ps->sz - 1);

}
void SLPopFront(SL* ps)
{
	assert(ps);
	/*assert(ps->sz > 0);*/
	/*int start = 0;
	while (start < ps->sz-1)
	{
		ps->a[start] = ps->a[start + 1];
		start++;
	}
	ps->sz--;*/

	/*int start = 1;
	while (start < ps->sz)
	{
		ps->a[start-1] = ps->a[start];
		start++;
	}
	ps->sz--;*/
	SLErase(ps, 0);

}


void SLInsert(SL* ps, int pos, SLdatatype x)
{
	assert(ps);
	assert(0 <= pos && pos <= ps->sz);
	SLCheckcapacity(ps);
	int end = ps->sz - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[pos] = x;
	ps->sz++;
}
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(0 <= pos && pos < ps->sz);
	assert(ps->sz > 0);
	int start = pos+1;
	while (start <ps->sz)
	{
		ps->a[start - 1] = ps->a[start];
		start++;
	}
	ps->sz--;


}

int SLFind(SL* ps, SLdatatype x)
{
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->sz; i++)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}
	return -1;

}
void SLModify(SL* ps, int pos, SLdatatype x)
{
	assert(ps);
	assert(0 <= pos && pos < ps->sz);
	ps->a[pos] = x;
}

test.c

#include"SedList.h"
void test1()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 4);
	SLPushBack(&s, 5);
	SLPushBack(&s, 6);
	SLprint(&s);
	SLDestroy(&s);

}
void test2()
{
	SL s;
	SLInit(&s);
	SLPushFront(&s, 4);
	SLPushFront(&s, 5);
	SLPushFront(&s, 6);
	SLprint(&s);
	SLDestroy(&s);

}
void test3()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 4);
	SLPushBack(&s, 5);
	SLPushBack(&s, 6);
	SLPopBack(&s);
	SLprint(&s);
	SLDestroy(&s);

}
void test4()
{
	SL s;
	SLInit(&s);
	SLPushFront(&s, 4);
	SLPushFront(&s, 5);
	SLPushFront(&s, 6);
	SLPopFront(&s);
	SLprint(&s);
	SLDestroy(&s);

}
void test5()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 1);
	SLPushBack(&s, 2);
	SLPushBack(&s, 3);
	SLPushBack(&s, 4);
	SLPushBack(&s, 5);
	SLPushBack(&s, 6);
	SLInsert(&s, 2, 30);
	SLprint(&s);


}
void test6()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 3);
	SLPushBack(&s, 4);
	SLPushBack(&s, 5);
	SLPushBack(&s, 6);
	int pos = SLFind(&s, 5);
	if (pos)
	{
		SLErase(&s, pos);
	}
	SLprint(&s);

	SLDestroy(&s);

}
void test7()
{
	SL s;
	SLInit(&s);
	SLPushFront(&s, 4);
	SLPushFront(&s, 5);
	SLPushFront(&s, 6);
	int pos = SLFind(&s, 5);
	if (pos)
	{
		SLErase(&s, pos);
	}
	SLprint(&s);
	SLDestroy(&s);

}
void test8()
{
	SL s;
	SLInit(&s);
	SLPushFront(&s, 4);
	SLPushFront(&s, 5);
	SLPushFront(&s, 6);
	int pos = SLFind(&s, 5);
	if (pos)
	{
		SLModify(&s, pos,30);
	}
	SLprint(&s);
	SLDestroy(&s);

}
int main()
{
	test1();
	test2();
	test3();
	test4();
	test5();
	test6();
	test7();
	test8();

}

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

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

相关文章

智能算法系列之蚁群算法

本博客封面由ChatGPT DALLE 2共同创作而成。 文章目录 前言1. 算法思想2. 算法流程3. 细节梳理4. 算法实现4.1 问题场景4.2 代码实现 代码仓库&#xff1a;IALib[GitHub] 前言 本篇是智能算法(Python复现)专栏的第五篇文章&#xff0c;主要介绍蚁群算法(Ant Colony Optimizati…

cmd@快捷键方式@静默执行命令

文章目录 ref快捷方式执行命令行或打开文件eg:直接打开某个文件 创建快捷方式eg:快捷方式运行命令 ref How can I execute a Windows command line in background? - Super Userstbrenner/SilentCMD: SilentCMD executes a batch file without opening the command prompt wi…

如何用100天时间,让CSDN的粉丝数从0狂飙到10000

2022年10月7日&#xff0c;正式开通了CSDN账号。但因为工作忙的原因&#xff0c;一直没有时间写博客文章&#xff0c;也没有投入精力在CSDN上。理所当然的&#xff0c;我的粉丝数量很稳定&#xff0c;一直保持着0的记录。 2023年春节假期过后&#xff0c;有点空闲时间了&#x…

Tre靶场通关过程(linpeas使用+启动项编辑器提权)

Tre靶场通关 通过信息收集获得到了普通用户账号密码&#xff0c;利用PEASS-ng的linpeas脚本进行提权的信息收集&#xff0c;根据已有信息进行提权。 靶机下载地址&#xff1a; https://download.vulnhub.com/tre/Tre.zip 信息收集 靶机IP探测&#xff1a;192.168.0.129 a…

java多线程下

ThreadLocal ThreadLocal 有什么用&#xff1f;通常情况下&#xff0c;我们创建的变量是可以被任何一个线程访问并修改的。如果想实现每一个线程都有自己的专属本地变量该如何解决呢&#xff1f;JDK 中自带的ThreadLocal类正是为了解决这样的问题。 ThreadLocal类主要解决的就…

解释表情包This code will never do anything!

目录 解释一下下面这段代码 #include int main(){ while (1) ;} void unreachable(){ std::cout <<"Hello world!"<;}<> 解释一下下面这段代码 $ clang loop.cpp -01 -Wall -o loop $ ./loop Hello world! 解释一下下面这段代码 #include <iostre…

python面试题

文章目录 赋值、深拷贝和浅拷贝有什么区别&#xff1f;元组和列表有什么不同&#xff1f;和is有什么不同&#xff1f;集合怎么转字典&#xff1f;字典怎么遍历&#xff1f;如何在Python中实现多线程&#xff1f;如何实现tuple和list的转换&#xff1f;实现删除一个list里面的重…

厉害的人是搭建平台的人,少数人

牛人是搭建平台的人&#xff0c;是少数人 创建平台才有难度 趣讲大白话&#xff1a;多数人的成就是借平台之力 【趣讲信息科技157期】 **************************** 认识清楚平台能力和个人能力 创建阿里巴巴公司太难 多数人是借阿里巴巴平台之力成就的 离开一个成功的平台&a…

汽车之家股票回购速度远低于预期,面临严重的资本投资风险

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 汽车之家的估值 基于对汽车之家&#xff08;ATHM&#xff09;2023财年非GAAP调整后每股收益2.55美元的普遍预测&#xff0c;市场给予汽车之家目前的估值约为2023财年预期正常化市盈率的13倍&#xff0c;猛兽财经认为这个市…

libevent高并发网络编程 - 01_libevent事件Event处理

文章目录 1. libevent事件驱动和事件处理简介2. 事件状态分析3. 事件Event常用API3.1 event_base_new()3.2 event_base_free()3.3 event_new()3.4 event_add()3.5 event_del()3.6 event_free()3.7 event_base_dispatch()3.8 event_base_loopbreak()3.9 evsignal_new()3.10 even…

继承与虚函数练习

Tip1 基类私有成员变量在子类中都不能直接访问&#xff0c;不是因为没有被子类继承&#xff0c;而是权限问题 Tip2 满足多态的父子对象&#xff0c;父类对象和子类对象前4个字节都是虚表指针&#xff08;vs2019下&#xff09;&#xff0c;父类与子类指向的是各自的虚表。 Tip…

云计算中的容器技术及其实践案例

第一章&#xff1a;什么是容器技术 随着云计算和DevOps的普及&#xff0c;容器技术在IT行业中越来越受到关注。容器是一种轻量级、可移植、可扩展的应用程序封装技术&#xff0c;可以将应用程序及其所有依赖项打包到一个独立的可执行文件中。相对于虚拟机技术&#xff0c;容器技…

无界AI绘画基础教程,和Midjourney以及Stable Diffusion哪个更好用?

本教程收集于&#xff1a;AIGC从入门到精通教程汇总 简单的总结 Midjourney&#xff0c;Stable Diffusion&#xff0c;无界AI的区别&#xff1f; Midjourney&#xff0c;收费&#xff0c;上手容易&#xff0c;做出来高精度的图需要自己掌握好咒语。咒语写不好&#xff0c;像…

【LLM大模型】LLM模型指令微调(更新中)

note 文章目录 note零、AIGC生成式模型1. 核心要素2. LLM evolutionary tree 二、LLM大模型1. ChatGLM&#xff08;1&#xff09;GLM-130B&#xff08;2&#xff09;ChatGLM-6B 2. LLaMA3. Chinese-LLaMA-Alpace4. Bloom5. PaLM 三、模型指令微调Reference 零、AIGC生成式模型 …

算法记录 | Day53 动态规划

1143.最长公共子序列 思路&#xff1a; 本题和动态规划&#xff1a;718. 最长重复子数组 (opens new window)区别在于这里不要求是连续的了&#xff0c;但要有相对顺序&#xff0c;即&#xff1a;“ace” 是 “abcde” 的子序列&#xff0c;但 “aec” 不是 “abcde” 的子序…

搭建DHCP、PXE、DNS、HTTP以及NFS服务综合实验的超详细讲解

文章目录 1.实验要求2.实验步骤2.1 步骤解答问题&#xff08;1&#xff09;2.1 步骤解答问题&#xff08;2&#xff09;2.1 步骤解答问题&#xff08;3&#xff09;2.1 步骤解答问题&#xff08;4&#xff09;2.1 步骤解答问题&#xff08;5&#xff09; 1.实验要求 &#xff…

Hadoop入门篇01---基础概念和部署教程

Hadoop入门篇01---基础概念和部署教程 Hadoop是什么Hadoop发展史Hadoop特点有哪些Hadoop版本Hadoop架构Hadoop 3.0新特性 Hadoop集群搭建集群简介集群部署方式standalone mode&#xff08;独立模式&#xff09;Pseudo-Distributed mode&#xff08;伪分布式模式&#xff09;Clu…

webpack的核心概念分别是什么,如何理解

这篇文章主要介绍了 title &#xff0c;小编觉得挺不错的&#xff0c;现在分享给大家&#xff0c;也给大家做个参考&#xff0c;希望大家通过这篇文章可以有所收获。 webpack 是一种前端资源构建工具&#xff0c;一个静态模块打包器&#xff08;module bundler&#xff09;&…

UE5.1.1C++从0开始(4.虚幻的接口以及交互功能)

这一个章节对于第一次接触虚幻的人来说可以说是最绕的一个点&#xff0c;因为老师突然给你塞了很多的概念&#xff0c;对于这一块的学习&#xff0c;我个人的推荐是&#xff1a;先把蓝图搞明白了&#xff0c;再对应到C的代码中&#xff0c;不然一定会被整的晕头转向。还是&…

安装ms sql server2000提示安装失败详见sqlstp.log日志

安装ms sql server2000提示安装失败详见sqlstp.log日志 目录 安装ms sql server2000提示安装失败详见sqlstp.log日志 一、可能的情况-其它位置不能有对它的引用 1.1、先安装了Delphi其options-环境变量-其中path中有sql&#xff0c;注册表将其清除 1. 2、注册表搜索-Micro…