一,预备知识
C语言基础知识:结构体,指针
顺序表概念
二,顺序表概念及结构
1)线性表
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是⼀种在实际中⼴泛使 ⽤的数据结构,常⻅的线性表:顺序表、链表、栈、队列、字符串...
线性表:逻辑一定连续 物理不一定连续
顺序表:逻辑连续 物理连续
2)顺序表
1,顺序表和数组的区别
顺序表的底层结构是数组,但增加了增删查改等功能
2,顺序表的分类
(1)静态顺序表
struct SeqList
{
int arr[N];
int size;//有效数据个数
};
静态顺序表缺陷:空间给少了不够⽤,给多了造成空间浪费
(2)动态顺序表
struct SeqList
{
SLDataType* arr;
int size; //有效数据个数
int capacity; //空间大小
};
可以动态增容(成倍数增加,一般以2倍形式)
3)动态顺序表的实现
首先建立SeqList.c, SeqList.h, test.c文件
SeqList.c 实现顺序表主要逻辑
SeqList.h 进行函数声明
test.c 测试代码可行性
(1)顺序表初始化
void SLInit(SL* ps);
void SLInit(SL* ps)
{
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
注:这里必须传地址
(2)顺序表的销毁
void SLDestroy(SL* ps);
void SLDestroy(SL* ps)
{
if (ps->arr) //等价于 if(ps->arr != NULL)
{
free(ps->arr);
}
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
(3)顺序表的尾插
void SLPushBack(SL* ps, SLDataType x);
ps:顺序表
x:插入数据
void SLPushBack(SL* ps, SLDataType x)
{
//if (ps == NULL)
//{
// return;
//}
assert(ps); //等价与assert(ps != NULL)
//ps->arr[ps->size] = x;
//++ps->size;
SLCheckCapacity(ps);
ps->arr[ps->size++] = x;
}
注意ps不能等于NULL因为NULL不能解引用 即使用assert(ps);
先判断是否有空间插入,如果空间不够则要申请空间,使用void SLCheckCapacity(SL* ps);函数
void SLCheckCapacity(SL* ps)
{
//插入数据之前先看空间够不够
if (ps->capacity == ps->size)
{
//申请空间
//malloc calloc realloc int arr[100] --->增容realloc
//三目表达式
int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));//要申请多大的空间
if (tmp == NULL)
{
perror("realloc fail!");
exit(1);//直接退出程序,不再继续执行
}
//空间申请成功
ps->arr = tmp;
ps->capacity = newCapacity;
}
}
用newCapacity来判断capacity是否0
申请空间有可能失败,可以用临时变量tmp来接收并判断
(4)顺序表的头插
前提:空间是否足够 即使用void SLCheckCapacity(SL* ps);函数
先让数据表中数据整体往后移
最后一步为arr[1] = arr[0];故判断因子为 i>0
for (int i = ps->size; i > 0; i--)
{
ps->arr[i] = ps->arr[i - 1];//arr[1] = arr[0]
}
故代码为
void SLPushFront(SL* ps, SLDataType x)
{
assert(ps);
SLCheckCapacity(ps);
//先让顺序表中已有的数据整体往后挪动一位
for (int i = ps->size; i > 0; i--)
{
ps->arr[i] = ps->arr[i - 1];//arr[1] = arr[0]
}
ps->arr[0] = x;
ps->size++;
}
(5)顺序表的打印
每次调试很麻烦,不妨设置一个顺序表打印的函数
此处不需要传指针,因为不需要修改顺序表
void SLPrint(SL s);
void SLPrint(SL s)
{
for (int i = 0; i < s.size; i++)
{
printf("%d ", s.arr[i]);
}
printf("\n");
}
(6)顺序表的尾删
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps)
{
assert(ps);
assert(ps->size);
//顺序表不为空
//ps->arr[ps->size - 1] = -1;
--ps->size;
}
顺序表数据不能为空 即assert(ps->size);
-1代表删除 但其实可以省略 即直接--ps->size; 因为其不影响顺序表的增删查改
(7)顺序表的头删
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps)
{
assert(ps);
assert(ps->size);
//数据整体往前挪动一位
for (int i = 0; i < ps->size-1 ; i++)
{
ps->arr[i] = ps->arr[i + 1]; //arr[size-2] = arr[size-1]
}
ps->size--;
}
最后一步为arr[size-2] = arr[size-1] 故判断因子为i < ps->size-1
(8)顺序表的指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x);
ps:顺序表位置
pos;指定位置下标
x;插入指定数据
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos <= ps->size);
//插入数据:空间够不够
SLCheckCapacity(ps);
//让pos及之后的数据整体往后挪动一位
for (int i = ps->size; i > pos ; i--)
{
ps->arr[i] = ps->arr[i - 1];//arr[pos+1] = arr[pos]
}
ps->arr[pos] = x;
ps->size++;
}
从后往前挪
最后一步为arr[pos+1] = arr[pos]; 故判断因子为 i > pos;
(9)顺序表的指定位置之前删除数据
void SLErase(SL* ps, int pos);
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--;
}
从前往后挪
最后一步为arr[size-2] = arr[size-1] 故判断因子为i < ps->size-1
(10)顺序表的查找
int SLFind(SL* ps, SLDataType x);
int SLFind(SL* ps, SLDataType x)
{
assert(ps);
for (int i = 0; i < ps->size; i++)
{
if (ps->arr[i] == x)
{
//找到啦
return i;
}
}
//没有找到
return -1;
}
4)总代码预览
SeqList.c
#include"SeqList.h"
void SLInit(SL* ps)
{
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
//顺序表的销毁
void SLDestroy(SL* ps)
{
if (ps->arr) //等价于 if(ps->arr != NULL)
{
free(ps->arr);
}
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
void SLCheckCapacity(SL* ps)
{
//插入数据之前先看空间够不够
if (ps->capacity == ps->size)
{
//申请空间
//malloc calloc realloc int arr[100] --->增容realloc
//三目表达式
int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));//要申请多大的空间
if (tmp == NULL)
{
perror("realloc fail!");
exit(1);//直接退出程序,不再继续执行
}
//空间申请成功
ps->arr = tmp;
ps->capacity = newCapacity;
}
}
//尾插
void SLPushBack(SL* ps, SLDataType x)
{
温柔的解决方式
//if (ps == NULL)
//{
// return;
//}
assert(ps); //等价与assert(ps != NULL)
//ps->arr[ps->size] = x;
//++ps->size;
SLCheckCapacity(ps);
ps->arr[ps->size++] = x;
}
//头插
void SLPushFront(SL* ps, SLDataType x)
{
assert(ps);
SLCheckCapacity(ps);
//先让顺序表中已有的数据整体往后挪动一位
for (int i = ps->size; i > 0; i--)
{
ps->arr[i] = ps->arr[i - 1];//arr[1] = arr[0]
}
ps->arr[0] = x;
ps->size++;
}
//void SLPrint(SL s)
//{
// for (int i = 0; i < s.size; i++)
// {
// printf("%d ", s.arr[i]);
// }
// printf("\n");
//}
void SLPopBack(SL* ps)
{
assert(ps);
assert(ps->size);
//顺序表不为空
//ps->arr[ps->size - 1] = -1;
--ps->size;
}
void SLPopFront(SL* ps)
{
assert(ps);
assert(ps->size);
//数据整体往前挪动一位
for (int i = 0; i < ps->size-1 ; i++)
{
ps->arr[i] = ps->arr[i + 1]; //arr[size-2] = arr[size-1]
}
ps->size--;
}
//在指定位置之前插入数据
// 1 2 size = 2
//pos 0 -1 100000
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos <= ps->size);
//插入数据:空间够不够
SLCheckCapacity(ps);
//让pos及之后的数据整体往后挪动一位
for (int i = ps->size; i > pos ; i--)
{
ps->arr[i] = ps->arr[i - 1];//arr[pos+1] = arr[pos]
}
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, SLDataType x)
//{
// assert(ps);
// for (int i = 0; i < ps->size; i++)
// {
// if (ps->arr[i] == x)
// {
// //找到啦
// return i;
// }
// }
// //没有找到
// return -1;
//}
SeqList.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"Contact.h"
//定义顺序表的结构
//#define N 100
//
静态顺序表
//struct SeqList
//{
// int arr[N];
// int size;//有效数据个数
//};
//typedef int SLDataType;//方便后续类型的替换
typedef peoInfo SLDataType;
//动态顺序表
typedef struct SeqList
{
SLDataType* arr;
int size; //有效数据个数
int capacity; //空间大小
}SL;
//typedef struct SeqList SL;
//顺序表初始化
void SLInit(SL* ps);
//顺序表的销毁
void SLDestroy(SL* ps);
void SLPrint(SL s);
//头部插入删除 / 尾部插入删除
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);
//指定位置之前插入/删除数据
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
int SLFind(SL* ps, SLDataType x);
以上就是本文所有内容,欢迎指导交流