C语言 数据结构之数组模拟实现顺序表流程详解

目录
  • 线性表和顺序表
    • 线性表
    • 顺序表
  • 静态顺序表
  • 动态顺序表

代码已经放在Gitee上,需要可以小伙伴可以去看看

用C语言数组模拟实现顺序表

Gitee

线性表和顺序表

线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列,这是我们广泛使用的数据结构。

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

常见的线性表:顺序表、链表、栈、队列、字符串…

顺序表

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

一般可以分为:

  • 静态顺序表:使用定长数组来存储元素
  • 动态顺序表:使用动态开辟的数组来储存元素

静态顺序表

//定义静态数组的大小,方便后续修改
#define MAX_SIZE 50

//重命名数组的数据类型,方便后续修改
typedef int SLDataType;

//定义结构体
//成员变量为数组和记录当前数据个数的变量
//重命名结构体数据类型,方便书写
typedef struct SeqList {

	SLDataType arr[MAX_SIZE];
	int size;

}SL;

//-----------------------------------------------------------------------------
//以下是一些常见的接口的声明

//顺序表初始化
//利用结构体类型创建一个静态顺序表变量后,可以对其进行初始化
void SLInit(SL* psl);

//打印顺序表
//把顺序表的值按照先后顺序打印出来
void SLPrint(SL* psl);

//检查顺序表是否已满
//每次进行加入数据的操作的时候需要先检查是否已经满了,如果满了就不能够插入了
void SLCheck(SL* psl);

//顺序表的尾插
//在顺序表的尾部在插入一个元素
//由于是数组加入数据很方便,直接使用数组下标就可以访问到
void SLPushBack(SL* psl, SLDataType data);

//顺序表的尾删
//删除顺序表尾部的数据
void  SLPopBack(SL* psl);

//顺序表的头插
//在顺序表的开头加入一个数据
void SLPushFront(SL* psl, SLDataType data);

//顺序表的头删
//把顺序表第一位数据删除
void SLPopFront(SL* psl);

//顺序表查找某个数据
//查找顺序表中是否存在某个数据,如果有就返回对应的下标
//如果找不到就返回-1
int SLFind(SL* psl, SLDataType x);

//顺序表在pos位置插入x
//在指定下标位置插入数据x,原来x位置的数据以及后面的数据往后移动
void SLInsert(SL* psl, size_t pos, SLDataType x);

//顺序表删除在pos位置的数据
void SLErase(SL* psl, size_t pos);

//顺序表某一位置数据的修改
void SLModify(SL* psl, size_t pos, SLDataType x);

以下是这些接口的具体实现

//顺序表初始化
void SLInit(SL* psl) {

	psl->arr[0] = 0;//此处只能初始化一个元素
	psl->size = 0;
}

//打印顺序表
void SLPrint(SL* psl) {

	int i = 0;

	if (psl->size) {

		for (i = 0; i < psl->size; i++) {

			//输出格式,记得根据SLDataTyped的类型来修改
			printf("%d ", psl->arr[i]);
		}
		printf("\n");
	}
	else {
		printf("Null\n");
	}

}

/*
//检查顺序表是否已满
void SLCheck(SL* psl) {

	if (psl->size == MAX_SIZE) {
		printf("顺序表已满,无法进行后续操作");
	}

}
*/

//顺序表的尾插
void SLPushBack(SL* psl, SLDataType data) {

	//插入数据要先检查空间是否已满

	//实现方法一不够好
	/*
	if (psl->size == MAX_SIZE) {

		printf("空间已满\n");
		return;
	}
	else {

		psl->arr[psl->size] = data;
		psl->size++;

	}*/

	//实现方法二,简单明了
	assert(psl->size != MAX_SIZE);

	psl->arr[psl->size] = data;
	psl->size++;
}

//顺序表的尾删
void  SLPopBack(SL* psl) {

	//判断是否还有元素可以删除
	assert(psl->size);

	psl->size--;

}

//顺序表的头插
void SLPushFront(SL* psl, SLDataType data) {

	assert(psl->size != MAX_SIZE);

	//src用来后移数据
	int src = psl->size;

	while (src >= 1) {
		psl->arr[src] = psl->arr[src - 1];
		src--;
	}
	psl->arr[src] = data;
	psl->size++;

}

//顺序表的头删
void SLPopFront(SL* psl) {

	//判断是否还有数据可以删除
	assert(psl->size);

	int src = 0;
	while (src < psl->size - 1) {

		psl->arr[src] = psl->arr[src + 1];
		src++;
	}
	psl->size--;
}

//顺序表查找某个数据
int SLFind(SL* psl, SLDataType x) {

	int i = 0;
	for (i = 0; i < psl->size; i++) {

		if (psl->arr[i] == x) {

			//找到了就返回该数据在顺序表中的位置
			return  i;
		}
	}
	//找不到就返回-1
	return -1;

}

//顺序表在pos位置插入x
void SLInsert(SL* psl, size_t pos, SLDataType x) {

	assert(psl->size < MAX_SIZE);
	assert(pos >= 0 && pos <= psl->size);//pos=0或者pos=size的时候,相当于头插,尾插

	int end = psl->size;

	while (end > pos) {

		psl->arr[end] = psl->arr[end - 1];
		end--;
	}
	psl->arr[pos] = x;
	psl->size++;

}

//顺序表删除在pos位置的数据
void SLErase(SL* psl, size_t pos) {

	assert(psl->size);
	assert(pos >= 0 && pos < psl->size);

	int start = pos + 1;
	while (start < psl->size) {

		psl->arr[start - 1] = psl->arr[start];
		start++;

	}
	psl->size--;
}

//顺序表某一位置数据的修改
void SLModify(SL* psl, size_t pos, SLDataType x) {

	assert(psl->size);
	assert(pos >= 0 && pos < psl->size);

	psl->arr[pos] = x;
}

上面代码的测试,我放在了Gitee上,需要的小伙伴可以参考一下

动态顺序表

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

//重命名SL的数据类型,方便后续修改
typedef int SLDataType;

//定义结构体
//成员变量为指向动态顺序表的指针,数据的个数,顺序表的容量
//capacity用来管理数组的总大小,如果size与capacity相等了,就表示数组已经满了需要扩容
//重定义结构体类型名称,方便操作
typedef struct SeqList {

	SLDataType* p;
	int size;
	int capacity;

}SL;

//----------------------------------------------------------------------
//一下是一些常用的接口,与静态顺序表差不多

//SL初始化
void SLInit(SL* ps);

//SL空间检查
//如若size与capacity相等表示数组已经满了,需要扩容
void SLCheckCapacity(SL* ps);

//SL打印
void SLPrint(SL* ps);

//SL销毁
//因为数组是动态开辟的,所以在最后不使用的数组的时候要释放空间
void SLDestory(SL* ps);

//SL尾插
void SLPushBack(SL* ps,SLDataType x);

//SL尾删
void SLPopBack(SL* ps);

//SL头插
void SLPushFront(SL* ps, SLDataType x);

//SL头删
void SLPopFront(SL* ps);

//SL查找某个数据
//如果能找到,返回该数据在顺序表中下标
int SLFind(SL* ps, SLDataType x);

//SL在pos位置插入x
void SLInsert(SL* ps, size_t pos, SLDataType x);

//SL删除pos位置的值
void SLErase(SL* ps, size_t pos);

//SL修改某一位置的数据
void SLModity(SL* ps, size_t pos, SLDataType x);

以下是具体的实现

//动态顺序表的实现

#include"DynamicSeqList.h"

//SL初始化
void SLInit(SL* ps) {

	ps->p = NULL;
	ps->capacity = 0;
	ps->size = 0;

}

//SL空间检查
void SLCheckCapacity(SL* ps) {

	if (ps->size == ps->capacity) {

		ps->capacity = (ps->capacity == 0) ? 5 : 2 * ps->capacity;

		SLDataType* tmp = (SLDataType*)realloc(ps->p, (ps->capacity) * sizeof(SLDataType));

		if (tmp == NULL) {

			printf("realloc fail\n");
			exit(-1);
		}

		ps->p = tmp;

	}

}

//SL打印
void SLPrint(SL* ps) {

	if (ps->size == 0) {

		printf("顺序表为空\n");

	}
	else {

		int i = 0;
		for (i = 0; i < ps->size; i++) {

			//打印格式记得根据SLDataType的类型来修改
			printf("%d ", ps->p[i]);

		}
		printf("\n");

	}

}

//SL销毁
//这里并没有完全销毁结构体s,只是把成员变量都赋值为0
void SLDestory(SL* ps) {

	free(ps->p);
	ps->p = NULL;
	ps->size = ps->capacity = 0;

}

//SL尾插
void SLPushBack(SL* ps, SLDataType x) {

	SLCheckCapacity(ps);

	ps->p[ps->size] = x;
	ps->size++;

}

//SL尾删
void SLPopBack(SL* ps) {

	//删除数据需要判断一下顺序表是否为空
	assert(ps->size > 0);
	ps->size--;

}

//SL头插
void SLPushFront(SL* ps, SLDataType x) {

	SLCheckCapacity(ps);

	int end = ps->size;
	while (end > 0) {

		ps->p[end] = ps->p[end - 1];
		end--;

	}
	ps->p[end] = x;
	ps->size++;
}

//SL头删
void SLPopFront(SL* ps) {

	//删除数据需要判断一下顺序表是否为空
	assert(ps->size > 0);

	int start = 0;
	while (start < ps->size - 1) {

		ps->p[start] = ps->p[start + 1];
		start++;

	}
	ps->size--;

}

//SL查找某个数据
int  SLFind(SL* ps, SLDataType x) {

	//需要判断顺序表是否为空,可以用assert,也可以用if判断
	assert(ps->size);

	int i = 0;
	for (i = 0; i < ps->size; i++) {

		if (x == ps->p[i]) {

			return i;
		}

	}
	return -1;

}

//SL在pos位置插入x
//当pos为0或者pos为size时,相当于头插、尾插
void SLInsert(SL* ps, size_t pos, SLDataType x) {

	SLCheckCapacity(ps);

	assert(pos >= 0 && pos <= ps->size);

	int end = ps->size;
	while (end > pos) {

		ps->p[end] = ps->p[end - 1];
		end--;
	}
	ps->p[end] = x;
	ps->size++;

}

//SL删除pos位置的值
void SLErase(SL* ps, size_t pos) {

	//判断要删除的位置是否在size之内
	assert(pos >= 0 && pos < ps->size);

	int start = pos + 1;
	while (start < ps->size) {

		ps->p[start - 1] = ps->p[start];
		start++;

	}
	ps->size--;

}

//SL修改某一位置的数据
void SLModity(SL* ps, size_t pos, SLDataType x) {

	//判断要修改的位置是否在size之内
	assert(pos >= 0 && pos < ps->size);

	ps->p[pos] = x;
}

同样的,我自己写的一些小测试也在Gitee上,需要的小伙伴可以去看看

到此这篇关于C语言 数据结构之数组模拟实现顺序表流程详解的文章就介绍到这了,更多相关数组模拟实现顺序表内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言编程数据结构线性表之顺序表和链表原理分析

    目录 线性表的定义和特点 线性结构的特点 线性表 顺序存储 顺序表的元素类型定义 顺序表的增删查改 初始化顺序表 扩容顺序表 尾插法增加元素 头插法 任意位置删除 任意位置添加 线性表的链式存储 数据域与指针域 初始化链表 尾插法增加链表结点 头插法添加链表结点 打印链表 任意位置的删除 双向链表 测试双向链表(主函数) 初始化双向链表 头插法插入元素 尾插法插入元素 尾删法删除结点 头删法删除结点 doubly-Linked list.c文件 doubly-Linkedlist.h 线性表的定

  • C语言实现顺序表的基本操作指南(注释很详细)

    目录 创建一个结构体用于存放顺序表相关数据 初始化顺序表 插入元素 先检查容量是否够用 删除元素 元素修改 查找元素 排序元素 元素反转 源码 SeqList.c test.c SeqList.h 总结 创建一个结构体用于存放顺序表相关数据 #define SEQTYPE int typedef struct SeqList { SEQTYPE* data; int size; //有效数据个数 int capacity; //容量 }SeqList; 初始化顺序表 void SeqListIn

  • 详解C语言之顺序表

    目录 一.思维导图 二.步骤 1.初始化 2.求表长 3.插入数据元素 4.删除数据元素 5.取出数据元素 按位查找 按位查找 所有代码 总结 一.思维导图 二.步骤 1.初始化 代码如下: void ListInit(SeqList *L) { L->size = 0; } 2.求表长 代码如下: int ListLength(SeqList L) { return L.size; } 3.插入数据元素 代码如下: int ListInsert(SeqList *L, int i, DataT

  • C语言 数据结构之数组模拟实现顺序表流程详解

    目录 线性表和顺序表 线性表 顺序表 静态顺序表 动态顺序表 代码已经放在Gitee上,需要可以小伙伴可以去看看 用C语言数组模拟实现顺序表 Gitee 线性表和顺序表 线性表 线性表(linear list)是n个具有相同特性的数据元素的有限序列,这是我们广泛使用的数据结构. 线性表在逻辑上是线性结构,也就说是连续的一条直线.但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储. 常见的线性表:顺序表.链表.栈.队列.字符串- 顺序表 顺序表是用一段物理地址连

  • 新手向超详细的C语言实现动态顺序表

    目录 一.各个函数接口的实现 1.1 不太好''李姐''的"容量检测函数" 1.2 在任意位置插入的函数"坑!" 1.3 在任意位置删除数据的函数 1.4 其余简单的接口函数 二.顺序表结构体声明与定义 三.头文件的调用 一.各个函数接口的实现 1.1 不太好''李姐''的"容量检测函数" 对顺序表进行插入数据时,需要判断顺序表的容量是否充足,增加数据的同时需要反复地检测容量,所以推荐直接将以上步骤封装成一个函数. 函数实现算法:若容量大小 ==

  • C语言编程简单却重要的数据结构顺序表全面讲解

    目录 前言 一.线性表定义 二.顺序表实现 1概念及结构 2静态顺序表 2.1实现顺序表接口,第一步要对顺序表进行初始化 2.2对顺序表的增删查改的接口函数(以尾插为例) 3动态顺序表 3.1动态顺序表初始化 3.2动态顺序表-尾插 3.3动态顺序表-头插 3.4动态顺序表-尾删 3.5动态顺序表-头删 3.6动态顺序表-任意位置插入数据 3.7动态顺序表-任意位置删除数据 结束 前言 本文主要介绍顺序表的定义和常见静态顺序表的用法. 一.线性表定义 线性表(line list)是n个具有相同特

  • C语言实现动态顺序表详解

    目录 什么是顺序表? 1. 定义顺序表结构体: 2. 初始化顺序表: 3. 销毁顺序表: 4. 打印顺序表: 5. 判断容量+扩容: 6. 头插数据: 7. 尾插数据: 8. 指定下标位置插入数据: 9. 删除数据: 10. 尾删数据: 11. 指定下标位置删除数据: 12. 查找数据: 13. 修改数据: 14. 源代码: 1. SeqList.h: 2. SeqList.cpp: 3. test.cpp: 15. 测试: 总结 什么是顺序表? 顺序表是在计算机内存中以数组的形式保存的线性表,

  • C语言数据结构之顺序表和单链表

    一.顺序表的创建.删除和插入 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> struct sqlist { int date[10]; int length; }; void InitList(sqlist& L) { for (int i = 0;i < 10;i++) { L.date[i] = 0; } L.length = 0; } void charu(sqlist& L) { for (int j =

  • C语言数据结构二叉树之堆的实现和堆排序详解

    目录 一.本章重点 二.堆 2.1堆的介绍 2.2堆的接口实现 三.堆排序 一.本章重点 堆的介绍 堆的接口实现 堆排序 二.堆 2.1堆的介绍 一般来说,堆在物理结构上是连续的数组结构,在逻辑结构上是一颗完全二叉树. 但要满足 每个父亲节点的值都得大于孩子节点的值,这样的堆称为大堆. 每个父亲节点的值都得小于孩子节点的值,这样的堆称为小堆. 那么以下就是一个小堆. 百度百科: 堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆. 若将和此次序列对应的一维数

  • Java数据结构顺序表用法详解

    目录 1.什么是顺序表 2.顺序表的基本功能和结构 3.顺序表基本功能的实现和解析 1.判断线性表是否为空 2.获取指定位置的元素 3.向线性表表添加元素 4.在位置i处插入元素 5.删除指定位置的元素,并返回该元素 6.查找t第一次出现的位置 7.手动扩容方法 1.什么是顺序表 在程序中,经常需要将一组(通常是同为某个类型的)数据元素作为整体管理和使用,需要创建这种元素组,用变量记录它们,传进传出函数等.一组数据中包含的元素个数可能发生变化(可以增加或删除元素). 对于这种需求,最简单的解决方

  • java数据结构和算法中哈希表知识点详解

    树的结构说得差不多了,现在我们来说说一种数据结构叫做哈希表(hash table),哈希表有是干什么用的呢?我们知道树的操作的时间复杂度通常为O(logN),那有没有更快的数据结构?当然有,那就是哈希表: 1.哈希表简介 哈希表(hash table)是一种数据结构,提供很快速的插入和查找操作(有的时候甚至删除操作也是),时间复杂度为O(1),对比时间复杂度就可以知道哈希表比树的效率快得多,并且哈希表的实现也相对容易,然而没有任何一种数据结构是完美的,哈希表也是:哈希表最大的缺陷就是基于数组,因

  • C语言数据结构实现银行模拟

    C语言数据结构实现银行模拟 实现代码: #include <stdio.h> #include <stdlib.h> #include <windows.h> #define MAX_WIN 20 #define MAX_STAY 100 typedef struct customer *link; struct customer { int stay; link next; }; link GUY(int stay, link next) { link c = mal

  • Java 数据结构深入理解ArrayList与顺序表

    目录 一.ArrayList简介 二.ArrayList的使用 1.ArrayList的构造 2.ArrayList的遍历 3.ArrayList的常见操作(方法) 4.ArrayList的扩容机制 三.模拟实现一个顺序表(Object[]) 一.ArrayList简介 在集合框架中,ArrayList是一个普通的类,实现了List接口,具体框架图如下: ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表. 二.ArrayList的使用 1.ArrayList的构造

  • 详解Python数据结构与算法中的顺序表

    目录 0. 学习目标 1. 线性表的顺序存储结构 1.1 顺序表基本概念 1.2 顺序表的优缺点 1.3 动态顺序表 2. 顺序表的实现 2.1 顺序表的初始化 2.2 获取顺序表长度 2.3 读取指定位置元素 2.4 查找指定元素 2.5 在指定位置插入新元素 2.6 删除指定位置元素 2.7 其它一些有用的操作 3. 顺序表应用 3.1 顺序表应用示例 3.2 利用顺序表基本操作实现复杂操作 0. 学习目标 线性表在计算机中的表示可以采用多种方法,采用不同存储方法的线性表也有着不同的名称和特

  • Java数组的声明与创建示例详解

    今天在刷Java题的时候,写惯了C++发现忘记了Java数组的操作,遂把以前写的文章发出来温习一下. 首先,数组有几种创建方式? Java程序中的数组必须先进行初始化才可以使用,所谓初始化,就是为数组对象的元素分配内存空间,并为每个数组元素指定初始值,而在Java中,数组是静态的,数组一旦初始化,长度便已经确定,不能再随意更改. 声明数组变量 首先必须声明数组变量,才能在程序中使用数组.下面是声明数组变量的语法: dataType[] arrayRefVar; // 首选的方法 或 dataTy

  • C/C++语言八大排序算法之桶排序全过程示例详解

    基本思路是将所有数的个位十位百位一直到最大数的最高位一步步装桶,先个位装桶然后出桶,直到最高位入桶出桶完毕. 首先我们要求出一个数组的最大数然后求出他的最大位数 //求最大位数的函数 int getmaxweisu(int* a,int len)// { int max = a[0]; for (int i = 0; i < len; i++) { if (max < a[i]) { max = a[i]; } } int count = 1; while (max/10) { count++

  • Java顺序查找算法详解

    目录 一.查找的基本概念 1.查找表 2.关键字 3.查找 4.动态查找表与静态查找表 5.平均查找长度 二.顺序查找法 1.概念 2.实践 一.查找的基本概念 在讲顺序查找法之前先来认识一些关于查找的基本概念. 1.查找表 由同一类型的数据元素(或记录)所构成的集合 数据元素之间存在完全松散的关系 非常灵活的数据结构 2.关键字 关键字是数据元素(或记录)中某个数据项的值,可以用它标识一个数据元素(或记录) 若关键字可以唯一地标识一个记录,则称之为主关键字 反之,若用以识别若干记录的关键字称之

随机推荐