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

本文介绍了C语言学习者在掌握基础语法后转向数据结构的学习,重点讲解了线性表和顺序表的概念,区分了逻辑结构和物理结构,并提供了动态顺序表的实现,包括初始化、销毁、打印、扩容和各种操作方法的代码示例。
摘要由CSDN通过智能技术生成

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

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

 

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

数据结构的相关介绍

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

(1)能够存储数据(顺序表,链表等结构)
(2)存储的数据能够方便查找

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

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

线性表:

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

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

从顺序表开始启航

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

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

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

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

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

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

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

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

顺序表头文件

代码的头文件

#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

//初始化
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;
}

打印

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

//打印
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;
	}
}

尾插

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

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

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

尾删 

直接把size减去1就ok

//尾删
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;
}

指定位置插入

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

//指定位置插入
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--;
}

最后附上最终代码 

总代码

SeqList.h

#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

#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

#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函数,检查一下

  • 22
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值