数据结构-->线性表-->顺序表

对我个人来说,C语言基础相关的知识基本学完了,随后就该学数据结构了,希望以后自己复习能够用上今天自己写的哈哈。

如果你不理解什么是物理结构和逻辑结构,这里附上一个链接:逻辑结构和物理结构:逻辑结构与物理结构_逻辑结构和物理结构-CSDN博客

看见我的备注了吗,一位不帅的帅哥。

数据结构的相关介绍

我们将数据结构拆分为两个词来理解

数据就是存储的信息,结构是组织数据的方式。

官方定义的数据结构的概念为:数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。数据结构反应数据的内部构成,即数据有哪部分构成,以什么方式构成,以及数据元素之间呈现的结构。

总结:

(1)能够存储数据(顺序表,链表等结构)

(2)存储的数据能够方便查找

数组是最基础的数据结构,我们除了数组还要学习更多数据结构的原因是:最基础的数据结构能够提供的操作已经不能完全满足复杂算法实现。

对数据结构中线性表的认识

线性表:

线性表是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列

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

从顺序表开始启航

顺序表和数组的区别:顺序表的底层结构是数组,对数组的封装,实现了常用的增删查改等接口。

顺序表分为静态顺序表和动态顺序表。

对静态顺序表来说:空间给少了不够用,给多了造成空间浪费。

也就是说老年机的通讯录就是静态顺序表。

这里附上老年机,商标就打码了,怕吃官司。

因此我们就写动态版本的顺序表了

对学校数据结构方面的忠告

好的,其实到这里呢,我就去手搓动态顺序表了,哈哈,幸运的是我完全写出来了,没看别人的,老师说过数据结构这块呢,就是要熟悉,重要的是代码,其实我觉得呢也没有别的办法,多写才是解药。

顺序表头文件

代码的头文件

cpp 复制代码
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* a;
	int size;
	int capacity;
}SL;

//初始化
void SLInit(SL* ps);
//销毁
void SLDestroy(SL* ps);
//打印
void SLPrint(SL* ps);
//扩容
void SLCheck(SL* ps);
//尾插
void SLPushBack(SL* ps, SLDataType x);
//尾删
void SLPopBack(SL* ps);
//头插
void SLPushFront(SL* ps, SLDataType x);
//头删
void SLPopFront(SL* ps);
//查找
int FindData(SL* ps, SLDataType x);
//指定位置插入
void InsertPush(SL* ps, int pos, SLDataType x);
//指定位置删除
void ErasePop(SL* ps, int pos);

初始化

这里没什么难度,就直接写就ok

cpp 复制代码
//初始化
void SLInit(SL* ps)
{
    ps->a = NULL;
    ps->capacity = ps->size = 0;
}

销毁

程序结束记得销毁,否则会发生内存泄漏,切记、切记、切记。

cpp 复制代码
//销毁
void SLDestroy(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->size = 0;
}

打印

对于打印,其实就直接遍历就ok

cpp 复制代码
//打印
void SLPrint(SL* ps)
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
}

扩容

这里的扩容,顾名思义就是扩大空间,他的作用是为了提供足够的空间

cpp 复制代码
//扩容
void SLCheck(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDataType* new = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));
		if (new == NULL)
		{
			perror("REALL0C FAIL");
			return;
		}
		ps->a = new;
		ps->capacity = newcapacity;
	}
}

尾插

尾插我们先检查我们的空间大小够不够,对于需要插入的接口来说,我们都要检查空间是否足够,

只要空间足够,就直接插入就ok了。

cpp 复制代码
//尾插
void SLPushBack(SL* ps,SLDataType x)
{
	assert(ps);
	SLCheck(ps);
	ps->a[ps->size++] = x;
}

尾删

直接把size减去1就ok

cpp 复制代码
//尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	ps->size--;
}

头插

头插就是要把原来的数据往后挪动,但是不能从前往后挪动,因为这样会覆盖之后还没挪动的数据,因此我们需要把数据从后往前开始往后挪动

cpp 复制代码
//头插
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheck(ps);
	for (int i = ps->size; i > 0; i--)
	{
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[0] = x;
	ps->size++;
}

头删

头删跟头插正好相反,额这算不算相当于没说

就是把数据从前往后开始往前面移动

cpp 复制代码
//头删
void SLPopFront(SL* ps)
{
	assert(ps);
	for (int i = 1; i < ps->size; i++)
	{
		ps->a[i-1] = ps->a[i];
	}
	ps->size--;
}

查找

查找就是遍历再加一层比较,值相等就返回下标

cpp 复制代码
//查找
int FindData(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}

指定位置插入

其实就是类似头插,注意for循环范围别搞错了,如果你怕搞错,这里提供一种方法,就是你只比较带入for循环的最大和最小情况,如果成立,那就是正确的。

cpp 复制代码
//指定位置插入
void InsertPush(SL* ps, int pos, SLDataType x)
{
    assert(ps);
    assert(ps->size);
    assert(pos >= 0 && pos <= ps->size);
    for (int i = ps->size; i > pos; i--)
    {
        ps->a[i] = ps->a[i - 1];
    }
    ps->a[pos] = x;
    ps->size++;
}

指定位置删除

类似头删

cpp 复制代码
//指定位置删除
void ErasePop(SL* ps, int pos)
{
	assert(ps);
	assert(ps->size);
	assert(pos >= 0 && pos < ps->size);
	for (int i = pos + 1; i < ps->size; i++)
	{
		ps->a[i - 1] = ps->a[i];
	}
	ps->size--;
}

最后附上最终代码

总代码

SeqList.h

cpp 复制代码
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* a;
	int size;
	int capacity;
}SL;

//初始化
void SLInit(SL* ps);
//销毁
void SLDestroy(SL* ps);
//打印
void SLPrint(SL* ps);
//扩容
void SLCheck(SL* ps);
//尾插
void SLPushBack(SL* ps, SLDataType x);
//尾删
void SLPopBack(SL* ps);
//头插
void SLPushFront(SL* ps, SLDataType x);
//头删
void SLPopFront(SL* ps);
//查找
int FindData(SL* ps, SLDataType x);
//指定位置插入
void InsertPush(SL* ps, int pos, SLDataType x);
//指定位置删除
void ErasePop(SL* ps, int pos);

SeqList.c

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
//初始化
void SLInit(SL* ps)
{
	ps->a = NULL;
	ps->capacity = ps->size = 0;
}
//销毁
void SLDestroy(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->size = 0;
}
//打印
void SLPrint(SL* ps)
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
}
//扩容
void SLCheck(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDataType* new = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));
		if (new == NULL)
		{
			perror("REALL0C FAIL");
			return;
		}
		ps->a = new;
		ps->capacity = newcapacity;
	}
}
//尾插
void SLPushBack(SL* ps,SLDataType x)
{
	assert(ps);
	SLCheck(ps);
	ps->a[ps->size++] = x;
}
//尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	ps->size--;
}
//头插
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheck(ps);
	for (int i = ps->size; i > 0; i--)
	{
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[0] = x;
	ps->size++;
}
//头删
void SLPopFront(SL* ps)
{
	assert(ps);
	for (int i = 1; i < ps->size; i++)
	{
		ps->a[i-1] = ps->a[i];
	}
	ps->size--;
}
//查找
int FindData(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}
//指定位置插入
void InsertPush(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(ps->size);
	assert(pos >= 0 && pos <= ps->size);
	for (int i = ps->size; i > pos; i--)
	{
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[pos] = x;
	ps->size++;
}
//指定位置删除
void ErasePop(SL* ps, int pos)
{
	assert(ps);
	assert(ps->size);
	assert(pos >= 0 && pos < ps->size);
	for (int i = pos + 1; i < ps->size; i++)
	{
		ps->a[i - 1] = ps->a[i];
	}
	ps->size--;
}

test.c

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
int main()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 1);
	SLPushBack(&s, 2);//1 2
	SLPrint(&s);
	printf("\n");
	SLPopBack(&s);//1
	SLPrint(&s);
	printf("\n");
	SLPushFront(&s,2);//2 1
	SLPrint(&s);
	printf("\n");
	SLPopFront(&s);//1
	SLPrint(&s);
	SLDestroy(&s);
	return 0;
}

运行test函数,测试各接口是否正确

运行一下test函数,检查一下

相关推荐
pianmian19 分钟前
完全平方数
数据结构·算法
XWXnb626 分钟前
数据结构:栈
数据结构
唐叔在学习30 分钟前
【唐叔学算法】第18天:解密选择排序的双重魅力-直接选择排序与堆排序的Java实现及性能剖析
数据结构·算法·排序算法
蹉跎x2 小时前
力扣1358. 包含所有三种字符的子字符串数目
数据结构·算法·leetcode·职场和发展
坊钰3 小时前
【Java 数据结构】移除链表元素
java·开发语言·数据结构·学习·链表
阿七想学习3 小时前
数据结构《排序》
java·数据结构·学习·算法·排序算法
越甲八千4 小时前
总结一下数据结构 树 的种类
数据结构
eternal__day4 小时前
数据结构(哈希表(中)纯概念版)
java·数据结构·算法·哈希算法·推荐算法
OTWOL5 小时前
两道数组有关的OJ练习题
c语言·开发语言·数据结构·c++·算法
不惑_5 小时前
List 集合安全操作指南:避免 ConcurrentModificationException 与提升性能
数据结构·安全·list