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

这篇具有很好参考价值的文章主要介绍了顺序表的基本操作(初始化,增,删,查,改等等)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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();

}

顺序表的基本操作(初始化,增,删,查,改等等)文章来源地址https://www.toymoban.com/news/detail-435987.html

到了这里,关于顺序表的基本操作(初始化,增,删,查,改等等)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】【数据结构】循环队列的基本操作(初始化、入队、出队、取队头元素、遍历输出队列、求队列长度)顺序队列的算法实现【附全代码】

    使用c++完成数据结构循环队列的基本操作,包括(初始化、入队、出队、取队头元素、遍历输出队列、求队列长度等),可直接编译运行。 队列 又称为 “先进先出” (FIFO)线性表。限定插入操作只能在队尾进行,而删除操作只能在队首进行。 循环队列 ——采用 顺序存储结构

    2023年04月16日
    浏览(42)
  • 【Pytorch】学习记录分享1——Tensor张量初始化与基本操作

    1. 基础资料汇总 资料汇总 pytroch中文版本教程 PyTorch入门教程 B站强推!2023公认最通俗易懂的【PyTorch】教程,200集付费课程(附代码)人工智能_机器 视频 1.PyTorch简介 2.PyTorch环境搭建 basic: python numpy pandas pytroch theory: study mlp cnn transform rnn model: AlexNet VGG ResNet Yolo SSD 2. Tensor张量

    2024年02月04日
    浏览(37)
  • C语言单链表实现初始化、创建、增、删、查等基本操作(详细)

    提示:文章参考王道的课程,相当于课程笔记 目录 一、单链表的定义及初始化 1、定义   2、初始化  1)不带头结点的单链表  2)带头节的单链表  二、单链表插入和删除 1)插入 1、按位序插入(带头结点) 2、按位插入(不带头结点)  3、指定结点的后插操作  4、指定结点

    2023年04月08日
    浏览(50)
  • C语言 队列(循环队列和链队初始化进出队等基本操作)

    目录 一、队列的定义  二、循环队列 1、 循环队列的储存结构 2、初始化 3、输出队列元素 4、入队 5、出队 6、取队头元素 7、求队列长度 8、源代码 三、链式队列 1、队列的链式存储结构表示 2、初始化 3.输出队列元素 4.入队 5.出队 6.取队头元素 7. 源代码 总结 队列 (Queue)

    2024年02月07日
    浏览(33)
  • 顺序表的基本操作

    目录 一.什么是顺序表 二.顺序表的基本操作   1.初始化 2.增容 3.尾插 4.头插 5.尾删 6.头删 7.指定位置插入 8.指定位置删除 9.打印 10.查找 11.销毁         顺序表是用一段 物理地址连续 的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据

    2024年01月20日
    浏览(38)
  • 【头歌】顺序表的基本操作

    任务描述 本关任务:编写顺序表的初始化、插入、遍历三个基本操作函数。 相关知识 顺序表的存储结构 顺序表的存储结构可以借助于高级程序设计语言中的数组来表示,一维数组的下标与元素在线性表中的序号相对应。线性表的顺序存储结构可用C语言中动态分配的一维数

    2024年04月08日
    浏览(64)
  • 数据结构实验---顺序表的合并---链表的基本操作---重点解析约瑟夫问题

    实验的写法多种多样,但本文并未采用 #define 定义容量的写法,这样写已经是很老旧过时的写法。所有实验主体采用均为动态开辟,后续如果利用 C++ 来写或许会应用更多语法… 本篇展示数据结构的两个实验 其中,重点分析约瑟夫问题 实验中代码的命名风格等均与下方博客

    2024年02月16日
    浏览(49)
  • 对顺序表的基本操作(增删查改),并编写makefile进行编

    1.定义顺序表结构体 2.创建顺序表 3.从尾部插入数据 4.遍历顺序表 5.从尾部删除数据 6.按下标插入数据 7.按下标删除数据 8.按下标修改数据 9.按下标查找数据 10.按数据修改数据 11..按数据查找位置 12.顺序表去重         删除重复数据         (提示:将先出现的数据与后面

    2024年02月20日
    浏览(37)
  • 数据结构 线性表的定义和基本操作(以顺序表为例)

    名人说:一花独放不是春,百花齐放花满园。——《增广贤文》 作者:Code_流苏(CSDN) (一个喜欢古诗词和编程的Coder😊) 以下代码个人分享出来,仅供学习交流,且仅在CSDN平台发布,未经授权禁止二次转发。 〇、线性表是什么? 1、定义 线性表 是具有 相同数据类型 的 n(

    2024年02月12日
    浏览(40)
  • 线性表的基本操作及在顺序存储及链式存储的实现

    一个数据结构的基本操作是指其最核心、最基本的操作。其他较复杂的操作可通过其基本操作来实现。线性表的主要操作如下 注意:1:基本操作的实现取决于采用哪种存储结构,存储结构不同,算法的实现也不同 2:“” 表示c++中的引用调用。若存入的变量是指针变量,且

    2024年02月13日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包