瞬时存取,无限可能:顺序表的独特魅力

嘿嘿,家人们,今天咱们来详细剖析数据结构中的顺序表,好啦,废话不多讲,开干!


目录

1:线性表

​2:顺序表 

2.1:概念以及结构

2.1.1:静态顺序表

2.1.2:动态顺序表

2.2:接口实现

2.2.1:Sequence_List.h

2.2.2:Sequence_List.c

2.2.2.1:初始化顺序表

2.2.2.2:检查容量

2.2.2.3:头插与尾插数据

2.2.2.4:头删与尾删数据 

2.2.2.5:任意位置的插入数据

2.2.2.6:任意位置的删除

2.2.2.7:查找元素与销毁顺序表

2.2.3:Test.c 

2.2.3.1:测试初始化与扩容

2.2.3.2:测试头插与尾插

2.2.3.3:测试头删与尾删 

2.2.3.4:测试任意位置的插入

2.2.3.5:测试任意位置的删除 

2.2.3.6:测试查找与销毁 

 3:总代码

3.1:Sequence_List.h

3.2:Sequence_List.c

3.3:Test.c


1:线性表

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

2:顺序表 

2.1:概念以及结构

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

2.1.1:静态顺序表

静态顺序表的特点在于使用定长数组存储元素.

缺点:空间给少了不够⽤,给多了造成空间浪费.

#define N 7
//进行函数与结构体的声明
typedef int SLDataType;

//定义顺序表的结构
typedef struct SeqList
{
	//存储数据
	SLDataType array[N];
	//记录有效数据
	int size;
}SeqList;

2.1.2:动态顺序表

动态顺序表的特点在于使用动态开辟的数组进行存储.

2.2:接口实现

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

2.2.1:Sequence_List.h

我们在Sequence_List.h 这一头文件里面完成以下工作

  1. 顺序表的定义.
  2. 相关的函数接口的声明.
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
//进行函数与结构体的声明
typedef int SLDataType;

//定义顺序表的结构
typedef struct SeqList
{
	//存储数据
	int* array;
	//记录有效数据
	int size;
	//记录容量
	int capacity;
}SeqList;

//顺序表初始化
void SeqInit(SeqList* ps);

//检查容量
void SeqCheckcapacity(SeqList* ps);

//尾插入数据
void SeqPushback(SeqList* ps, SLDataType value);

//头插入数据
void SeqPushfront(SeqList* ps, SLDataType value);

//任意位置下标的插入
void SeqInsertPos(SeqList* ps, int position, SLDataType value);

//打印顺讯表
void SeqPrint(SeqList* ps);

//尾删数据
void SeqPopback(SeqList* ps);

//头删数据
void SeqPopfront(SeqList* ps);

//任意位置数据的删除
void SeqErasePos(SeqList* ps, int position);

//查找元素
int SeqFindelement(SeqList* ps, SLDataType value);

//销毁顺序表
void SeqDestory(SeqList* ps);

2.2.2:Sequence_List.c

2.2.2.1:初始化顺序表

第一步首先是初始化顺序表.

void SeqInit(SeqList * ps)
{
    //防止空指针与野指针的传递
    assert(ps);
    ps->array = NULL;
    ps->capacity = 0;
    ps->size = 0;
}

2.2.2.2:检查容量

我们实现的是一个动态增长的顺序表,那么因此就需要就要检查容量,容量不够则需要进行扩容. 

void SeqCheckcapacity(SeqList * ps)
{
    assert(ps);
    //有效数据等于容量则进行扩容
    if(ps->size == ps->capacity)
    {
        //若为0则将其初始容量为4,反之则进行二倍扩容
        int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
        //使用realloc进行扩容;如果为空指针,就等价于malloc(sizeof(SeqList) * newcapcity);防止扩容失败将原地址覆盖
        SLDataType* temp = (SLDataType*)realloc(ps->array, sizeof(SLDataType) * newcapacity);
        if(temp == NULL)
        {
            perror("realloc fail\n");
            exit(1);
        }
        ps->array = temp;
        ps->capacity = newcapacity;
        printf("扩容成功\n");
    }
}

 

2.2.2.3:头插与尾插数据

那么接下来我们就要去实现数据的插入了,首先是头插数据与尾插数据.

  1. 在插入数据前,我们首先得检查其空间容量是否足够.
  2. 头插数据的话,那么我们就得将已有的数据向后挪动.
  3. 尾插数据的话,直接在尾部插入即可.
//头插入数据
void SeqPushfront(SeqList* ps, SLDataType value)
{
    assert(ps);
    //插入数据前检查容量
    SeqCheckcapacity(ps);
    for(int i = ps->size - 1; i >=0 ; i--)
    {
        //进行挪动数据
        ps->array[i + 1] = ps->array[i];
    }
    ps->array[0] = value;
    ps->size++;
}

void SeqPushback(SeqList* ps, SLDataType value)
{
    assert(ps);
    //插入数据前检查容量
    SeqCheckcapacity(ps);
    //数组下标从0开始
    ps->array[ps->size] = value;
    ps->size++;
}

2.2.2.4:头删与尾删数据 

那么接下来我们就要去实现数据的删除了,首先是头删数据与尾删数据.

  1. 在删除数据前,我们首先得检查里面是否有数据即有效数据不为0.
  2. 头删数据的话,那么我们就得将已有的数据向前挪动进行覆盖即可.
  3. 尾删数据的话,直接在尾部删除即可.
//头删数据
void SeqPopfront(SeqList* ps)
{
    assert(ps);
    //确保有效数据不为0
    assert(ps->size);
    for (int i = 0; i < ps->size - 1; i++)
    {
        ps->array[i] = ps->array[i + 1];
    }
    ps->size--;
}

//尾删数据
void SeqPopback(SeqList* ps)
{
    assert(ps);
    //确保有效数据不为0
    assert(ps->size);
    //有效数据 - 1即可达到尾删的效果
    ps->size--;

}

2.2.2.5:任意位置的插入数据
//任意位置下标的插入
void SeqInsertPos(SeqList* ps, int position, SLDataType value)
{
    assert(ps);
    //确保插入的位置是有效的
    assert(position >= 1 && position <= ps->size + 1);
    SeqCheckcapacity(ps);
    for(int i = ps->size - 1; i >= position - 1; i--)
    {
        //从后往前挪动覆盖
        ps->array[i + 1] = ps->array[i];
    }
    //插入数据
    ps->array[position - 1] = value;
    ps->size++;
}

2.2.2.6:任意位置的删除
//任意位置数据的删除
void SeqErasePos(SeqList* ps, int position)
{
    assert(ps);
    //确保插入的位置是有效的
    assert(position >= 1 && position <= ps->size + 1);
    for(int i = position - 1; i < ps->size - 1; i++)
    {
        //从前向后挪动覆盖
        ps->array[i] = ps->array[i + 1];
    }
    ps->size--;
}
//查找元素
int SeqFindelement(SeqList* ps, SLDataType value)
{
    assert(ps);
    for(int i = 0; i < ps->size; i++)
    {
        if (ps->array[i] == value)
            return i + 1;
    }
    return 0;
}



//销毁顺序表
void SeqDestory(SeqList* ps)
{
    assert(ps);
    free(ps->array);
    ps->array = NULL;
    ps->size = 0;
    ps->capacity = 0;
}

 

2.2.2.7:查找元素与销毁顺序表

 

2.2.3:Test.c 

2.2.3.1:测试初始化与扩容
#define _CRT_SECURE_NO_WARNINGS
#include "List.h"

void TestInitAndCheckCapcity(SeqList * ps)
{
	SeqInit(ps);
	SeqCheckcapacity(ps);
}
int main()
{
	SeqList s1;
	TestInitAndCheckCapcity(&s1);
	return 0;
}

2.2.3.2:测试头插与尾插
#define _CRT_SECURE_NO_WARNINGS
#include "List.h"
void TestPushFrontAndPushBack(SeqList* ps)
{
	SeqInit(ps);
	//尾插数据后
	SeqPushback(ps,5);
	SeqPushback(ps,6);
	SeqPushback(ps,7);
	SeqPrint(ps);
	//头插数据后
	SeqPushfront(ps, 4);
	SeqPushfront(ps, 3);
	SeqPushfront(ps, 2);
	SeqPrint(ps);
}
int main()
{
	SeqList s1;
	TestPushFrontAndPushBack(&s1);
	return 0;
}

2.2.3.3:测试头删与尾删 
#define _CRT_SECURE_NO_WARNINGS
#include "List.h"

void TestPopFrontAndPopBack(SeqList* ps)
{
	SeqInit(ps);
	//尾插数据后
	SeqPushback(ps, 5);
	SeqPushback(ps, 6);
	SeqPushback(ps, 7);
	SeqPrint(ps);
	//头插数据后
	SeqPushfront(ps, 4);
	SeqPushfront(ps, 3);
	SeqPushfront(ps, 2);
	SeqPrint(ps);
	//头删数据后
	printf("头删数据后\n");
	SeqPopfront(ps);
	SeqPopfront(ps);
	SeqPrint(ps);
	//尾删数据后
	printf("尾删数据后\n");
	SeqPopback(ps);
	SeqPopback(ps);
	SeqPrint(ps);
}
int main()
{
	SeqList s1;
	TestPopFrontAndPopBack(&s1);
	return 0;
}

2.2.3.4:测试任意位置的插入
#define _CRT_SECURE_NO_WARNINGS
#include "List.h"

void TestInsertPos(SeqList* ps)
{
	SeqInit(ps);
	//尾插数据后
	SeqPushback(ps, 5);
	SeqPushback(ps, 6);
	SeqPushback(ps, 7);
	SeqPrint(ps);
	//头插数据后
	SeqPushfront(ps, 4);
	SeqPushfront(ps, 3);
	SeqPushfront(ps, 2);
	SeqPrint(ps);
	//在第三个位置插入,即在下标为2的位置插入
	SeqInsertPos(ps, 3, 8);
	SeqInsertPos(ps, 5, 9);
	SeqInsertPos(ps, 9, 25);
	SeqPrint(ps);
}
int main()
{
	SeqList s1;
	TestInsertPos(&s1);
	return 0;
}

2.2.3.5:测试任意位置的删除 
#define _CRT_SECURE_NO_WARNINGS
#include "List.h"

void TestErasePos(SeqList * ps)
{
	SeqInit(ps);
	//尾插数据后
	SeqPushback(ps, 5);
	SeqPushback(ps, 6);
	SeqPushback(ps, 7);
	SeqPrint(ps);
	//在第三个位置插入,即在下标为2的位置插入
	SeqInsertPos(ps, 4, 8);
	SeqInsertPos(ps, 5, 9);
	SeqInsertPos(ps, 6, 25);
	SeqPrint(ps);
	SeqErasePos(ps, 6);
	SeqErasePos(ps, 4);
	SeqErasePos(ps, 1);
	SeqPrint(ps);
}
int main()
{
	SeqList s1;
	TestErasePos(&s1);
	return 0;
}

2.2.3.6:测试查找与销毁 
#define _CRT_SECURE_NO_WARNINGS
#include "List.h"

void TestDestoryAndFind(SeqList * ps)
{
	SeqInit(ps);
	//尾插数据后
	SeqPushback(ps, 5);
	SeqPushback(ps, 6);
	SeqPushback(ps, 7);
	SeqPrint(ps);
	//在第三个位置插入,即在下标为2的位置插入
	SeqInsertPos(ps, 4, 8);
	SeqInsertPos(ps, 5, 9);
	SeqInsertPos(ps, 6, 25);
	SeqPrint(ps);
	printf("找到了,在第%d个位置\n", SeqFindelement(ps,25));
	printf("找到了,在第%d个位置\n", SeqFindelement(ps,5));
	SeqDestory(ps);
	SeqPrint(ps);
}
int main()
{
	SeqList s1;
	TestDestoryAndFind(&s1);
	return 0;
}

 3:总代码

3.1:Sequence_List.h

#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
//进行函数与结构体的声明
typedef int SLDataType;

//定义顺序表的结构
typedef struct SeqList
{
	//存储数据
	int* array;
	//记录有效数据
	int size;
	//记录容量
	int capacity;
}SeqList;

//顺序表初始化
void SeqInit(SeqList* ps);

//检查容量
void SeqCheckcapacity(SeqList* ps);

//尾插入数据
void SeqPushback(SeqList* ps, SLDataType value);

//头插入数据
void SeqPushfront(SeqList* ps, SLDataType value);

//任意位置下标的插入
void SeqInsertPos(SeqList* ps, int position, SLDataType value);

//打印顺讯表
void SeqPrint(SeqList* ps);

//尾删数据
void SeqPopback(SeqList* ps);

//头删数据
void SeqPopfront(SeqList* ps);

//任意位置数据的删除
void SeqErasePos(SeqList* ps, int position);

//查找元素
int SeqFindelement(SeqList* ps, SLDataType value);

//销毁顺序表
void SeqDestory(SeqList* ps);

3.2:Sequence_List.c

#define  _CRT_SECURE_NO_WARNINGS
#include "Sequence_list.h"

//初始化顺序表
void SeqInit(SeqList* ps)
{
	assert(ps);
	ps->array = NULL;
	ps->capcity = 0;
	ps->size = 0;
}

//检查容量
void SeqCheckcapcity(SeqList * ps)
{
	assert(ps);
	//有效数据等于容量,进行扩容
	if (ps->size == ps->capcity)
	{
		int newcapcity = ps->capcity == 0 ? 4 : ps->capcity * 2;
		//使用realloc进行扩容;如果为空指针,就等价于malloc(sizeof(SeqList) * newcapcity);防止扩容失败将原地址覆盖
		SLDataType * tmp = (SLDataType *)realloc(ps->array, sizeof(SLDataType) * newcapcity);
		if (tmp == NULL)
		{
			perror("realloc");
			return;
		}
		ps->array = tmp;
		ps->capcity = newcapcity;
		printf("扩容成功\n");
	}
}

//顺序表打印
void SeqPrint(SeqList * ps)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->array[i]);
	}
	printf("\n");
}

//头插数据
void SeqPushfront(SeqList* ps, SLDataType value)
{
	assert(ps);
	//插入前检查容量
	SeqCheckcapcity(ps);
	//数据从后向前挪动
	for (int i = ps->size - 1; i >= 0; i--)
	{
		ps->array[i + 1] = ps->array[i];
	}
	ps->array[0] = value;
	ps->size++;
}

//尾插数据
void SeqPushback(SeqList* ps, SLDataType value)
{
	assert(ps);
	//插入前检查容量
	SeqCheckcapcity(ps);
	ps->array[ps->size] = value;
	ps->size++;
}
//任意下标位置的插入 
void SeqInsertPos(SeqList* ps, int position, SLDataType value)
{
	assert(ps);
	//确保正确插入
	assert(position >= 1 && position <= ps->size + 1);
	SeqCheckcapcity(ps);
	for (int i = ps-> size - 1 ; i >= position - 1; i--)
	{
		ps->array[i + 1] = ps->array[i];
	}
	ps->array[position - 1] = value;
	ps->size++;
}

//尾删数据
void SeqPopback(SeqList* ps)
{
	assert(ps);
	//删除前确保有效数据不为0
	assert(ps->size);
	ps->size--;
}

//头删数据
void SeqPopfront(SeqList* ps)
{
	assert(ps);
	//确保有效数据不为0
	assert(ps->size);
	for (int i = 0; i < ps->size; i++)
	{
		ps->array[i] = ps->array[i + 1];
	}
	ps->size--;
}

//任意位置的删除

void SeqErasePos(SeqList* ps,int position)
{
	assert(ps);
	assert(position >= 1 && position <= ps->size + 1);
	for (int i = position - 1; i < ps->size; i++)
	{
		//从后往前挪动覆盖
		ps->array[i] = ps->array[i + 1];
	}
	ps->size--;
}

int SeqFindelement(SeqList* ps, SLDataType value)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if(value == ps->array[i])
		{
			return (i + 1);
		}
	}
	return 0;
}

//销毁顺序表
void SeqDestory(SeqList* ps)
{
	//不为空则进行销毁
	assert(ps);
	free(ps->array);
	ps->array = NULL;
	ps->capcity = 0;
	ps->size = 0;
}

3.3:Test.c

#define  _CRT_SECURE_NO_WARNINGS
#include "Sequence_list.h"

//测试尾插与头插与打印
void test1(SeqList * ps)
{
	//初始化
	SeqInit(ps);

	//尾插
	SeqPushback(ps, 1);
	SeqPushback(ps, 2);
	SeqPushback(ps, 3);
	SeqPushback(ps, 4);
	SeqPushback(ps, 5);
	printf("尾插之后:>");
	SeqPrint(ps);

	//头插
	SeqPushfront(ps, 40);
	SeqPushfront(ps, 30);
	SeqPushfront(ps, 20);
	SeqPushfront(ps, 10);
	printf("头插之后:>");
	SeqPrint(ps);
}

//测试尾删与头删
void test2(SeqList* ps)
{
	//尾删
	SeqPopback(ps);
	SeqPopback(ps);
	SeqPopback(ps);
	printf("尾删之后:>");
	SeqPrint(ps);
	//头删
	SeqPopfront(ps);
	SeqPopfront(ps);
	printf("头删之后:>");
	SeqPrint(ps);
}

//测试任意位置的插入与删除
void test3(SeqList * ps)
{
	SeqInsertPos(ps, 1, 20);
	printf("在第1个位置插入之后:>");
	SeqPrint(ps);


	SeqInsertPos(ps, 4, 3);
	printf("在第4个位置插入之后:>");
	SeqPrint(ps);
	
	SeqInsertPos(ps, 5, 4);
	printf("在第5个位置插入之后:>");
	SeqPrint(ps);
	
	SeqInsertPos(ps, 6, 5);
	printf("在第6个位置插入之后:>");
	SeqPrint(ps);

	SeqErasePos(ps, 3);
	printf("删除第3个位置的元素之后:>");
	SeqPrint(ps);

	SeqErasePos(ps, 7);
	printf("删除第7个位置的元素之后:>");
	SeqPrint(ps);

}

test4(SeqList * ps)
{
	int result = SeqFindelement(ps, 20);
	if (result)
	{
		printf("在第%d个位置\n", result);
	}
	else
	{
		printf("无法找到\n");
	}
	
}

int main()
{
	SeqList s1;
	test1(&s1);
	test2(&s1);
	test3(&s1);
	test4(&s1);
	//销毁顺序表
	SeqDestory(&s1);
}


 好啦,uu们,数据结构顺表表这部分滴详细内容博主就讲到这里啦,如果uu们觉得博主讲的不错的话,请动动你们滴小手给博主点点赞,你们滴鼓励将成为博主源源不断滴动力,同时也欢迎大家来指正博主滴错误~

评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值