【数据结构】顺序表
本文是小编巩固自身而作,如有错误,欢迎指出!
1.线性表
线性表(linearlist)是n个具有相同特性的数据元素的有限序列。线性表是⼀种在实际中⼴泛使⽤的 数据结构,常⻅的线性表:顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构,也就说是连续的⼀条直线。但是在物理结构上并不⼀定是连续的,线性 表在物理上存储时,通常以数组和链式结构的形式存储。
2.顺序表
顺序表是什么?
顺序表是⽤⼀段物理地址连续的存储单元依次存储数据元素的线性结构,⼀般情况下采⽤数组 存储。
说通俗一点就是顺序表是对数组的封装,在数组的基础上,增加了增删数据,查找修改顺序的功能。
2.1顺序表的分类
2.11静态顺序表
静态顺序表即一个定长的数组,不能对其进行大小的改变
我们用下面代码声明一个简单的静态顺序表
typedef int sldatatype;//方面我们改变储存的数据类型
#define N 7
typedef struct seqlist
{
sldatatype a[N];//定长数组
int size;//有效数据个数
}
静态数据表的缺陷就是:空间给少了会不够用,给多了又会造成空间浪费
2.12动态顺序表
而动态顺序表即可以进行增删,扩容等等操作;
下面我们先声明一个动态顺序表
typedef int sldtype;
struct seqlist
{sldtype* arr;int size;//有效数据个数int capacity;//空间容量
};
typedef struct seqlist SL;
下面我们看看如何实现一个完整的顺序表
2.121 顺序表的初始化
void slinit(SL*);//顺序表的声明
void slinit(SL* ps)
{ps->arr = NULL;ps->size = 0;ps->capacity = 0;
}
先将所有的数据置空。
2.122 顺序表的头插与尾插
void slpushback(SL* ps, sldtype x);//尾插
void slpushfrond(SL* ps, sldtype x);//头插
而当我们需要插入数据时,首先就要考虑一点,即空间是否足够,如果不够的话我们就需要进行扩容,所以我们先看怎么能够扩容。
void slcheckcapacity(SL* ps);//增容函数
void slcheckcapacity(SL* ps)//增容函数
{if (ps->capacity == ps->size){//增容int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;sldtype* tmp = (sldtype*)realloc(ps->arr, newcapacity * sizeof(sldtype));//不直接使用ps防止扩容失败将其质空导致数据丢失if (tmp == NULL){perror("realloc fail");exit(1);}ps->arr = tmp;ps->capacity = newcapacity;}
}
其主要思路就是当数据的储存量到达了极限时,我们进行增容,我的一开始设置的大小是4个储存类型的大小,当其大小不够时,进行整数倍扩容
了解怎么扩容后我们就看看怎么插入
首先是尾插,只用直接在最后的位置添加数据即可
void slpushback(SL* ps, sldtype x)
{//判断空间是否足够slcheckcapacity(ps);//当空间足够的时候ps->arr[ps->size++] = x;//插入数据}
而头插就需要将之前的数据整体向后挪动
void slpushfrond(SL* ps, sldtype x)
{if (ps == NULL){return;}slcheckcapacity(ps);//将数组的所有数据向后挪动一位for (int i = ps->size;i > 0;i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[0] = x;++ps->size;}
2.123头删和尾删
先看比较好实现的尾删
void slpopback(SL* ps)
{assert(ps&&ps->size);--ps->size;
}
直接将size所在的位置向前移动就行了,但要考虑size为0的情况,我们采用断言
然后是头删
void slpopfromt(SL* ps)
{assert(ps && ps->size);for (int i = 0;i < ps->size - 1;i++){ps->arr[i] = ps->arr[i + 1];}--ps->size;
}
思路就是将所有的数据向左移动
2.124在指定位置插入和删除数据
先看插入数据
void slinsert(SL* ps, int pos, sldtype x)
{slcheckcapacity(ps);assert(ps);assert(pos >= 0 && pos <= ps->size);for (int i = ps->size;i > pos;i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[pos] = x;++ps->size;}
其思路就是将所有的数据从插入位置挪一格,然后将挪出的位置留给插入数据
然后是删除数据
void slerase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);for (int i = pos;i < ps->size - 1;i++){ps->arr[i] = ps->arr[i + 1];}--ps->size;
}
其思路就是将所有数据项删除的地方移动,将其覆盖
2.125 查找指定数据
int slfind(SL* ps, sldtype x)
{for (int i = 0;i < ps->size;i++){if (ps->arr[i] == x){return i;}}return -1;
}
简单的条件判断,不做解释
2.126顺序表的销毁
void sldestroy(SL* ps)
{assert(ps);if (ps->arr)free(ps->arr);ps->arr = NULL;ps->capacity =ps->size = 0;
}
即将所有数据置空,并释放动态内存
3.完整代码展示
3.1头文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
typedef int sldtype;
struct seqlist
{sldtype* arr;int size;//有效数据个数int capacity;//空间容量};
typedef struct seqlist SL;
void slinit(SL*);//顺序表的初始化
void slpushback(SL* ps, sldtype x);//尾插
void slpushfrond(SL* ps, sldtype x);//头插
void slcheckcapacity(SL* ps);//增容函数
void slprint(SL* ps);//打印顺序表
void slpopback(SL* ps);//尾删void slpopfromt(SL* ps);//头删
void slinsert(SL* ps ,int pos, sldtype x);//在指定位置(下标)前插入数据
void slerase(SL* ps, int pos);//删除指定位置的数据
int slfind(SL* ps, sldtype x);//查找指定数据
void sldestroy(SL* ps);//销毁顺序表
3.2实现文件
#define _CRT_SECURE_NO_WARNINGS#include"seqlist.h"
#include<assert.h>
void slinit(SL* ps)
{ps->arr = NULL;ps->size = 0;ps->capacity = 0;
}
void slcheckcapacity(SL* ps)//增容函数
{if (ps->capacity == ps->size){//增容int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;sldtype* tmp = (sldtype*)realloc(ps->arr, newcapacity * sizeof(sldtype));//不直接使用ps防止扩容失败将其质空导致数据丢失if (tmp == NULL){perror("realloc fail");exit(1);}ps->arr = tmp;ps->capacity = newcapacity;}
}
void slpushback(SL* ps, sldtype x)
{//判断空间是否足够slcheckcapacity(ps);//当空间足够的时候ps->arr[ps->size++] = x;//插入数据}
void slpushfrond(SL* ps, sldtype x)
{if (ps == NULL){return;}slcheckcapacity(ps);//将数组的所有数据向后挪动一位for (int i = ps->size;i > 0;i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[0] = x;++ps->size;}
void slpopback(SL* ps)
{assert(ps&&ps->size);--ps->size;
}
void slprint(SL* ps)
{for (int i = 0;i < ps->size;i++){printf("%d ", ps->arr[i]);}printf("\n");
}
void slpopfromt(SL* ps)
{assert(ps && ps->size);for (int i = 0;i < ps->size - 1;i++){ps->arr[i] = ps->arr[i + 1];}--ps->size;
}
void slinsert(SL* ps, int pos, sldtype x)
{slcheckcapacity(ps);assert(ps);assert(pos >= 0 && pos <= ps->size);for (int i = ps->size;i > pos;i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[pos] = x;++ps->size;}
void slerase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);for (int i = pos;i < ps->size - 1;i++){ps->arr[i] = ps->arr[i + 1];}--ps->size;
}
int slfind(SL* ps, sldtype x)
{for (int i = 0;i < ps->size;i++){if (ps->arr[i] == x){return i;}}return -1;
}
void sldestroy(SL* ps)
{assert(ps);if (ps->arr)free(ps->arr);ps->arr = NULL;ps->capacity =ps->size = 0;
}
3.3测试文件
#define _CRT_SECURE_NO_WARNINGS
#include"seqlist.h"
void test1()
{SL sl;slinit(&sl);slpushback(&sl, 1);slpushback(&sl, 2);slpushback(&sl, 3);slpushback(&sl, 4);slpushback(&sl, 5);slpushfrond(&sl, 5);slpopback(&sl);slpopfromt(&sl);slinsert(&sl, 1, 5);slerase(&sl, 2);sldestroy(&sl);slprint(&sl);int find = slfind(&sl, 3);/*if (find>=0){printf("找到了\n");printf("下标是:%d\n", find);}else{printf("没找到\n");}*//*printf("%d", sl.size);*/}
int main()
{test1();return 0;
}
今天的内容就到这里了,后续会继续更新,感谢阅读!