最近有了考研的打算,而且之前也很少接触数据结构和算法之类的东西,所以最近开始了学起了数据结构。这肯定是离不开写代码的,这就把平时练习时写的代码贴出来做个记录也算分享了把,纯纯小白一枚,欢迎大佬指点。
顺序表
- 头文件和全局参数
#include <stdlib.h>
#define MAX_SIZE 10
- 定义一个结构体
struct SeqList {
// 指针指向一个内存地址
int * data;
// 最大长度
int maxSize;
// 当前长度
int length;
};
- 初始化
/**
* 初始化
*/
SeqList initSeqList() {
// 声明一个刚刚定义的结构体
SeqList l;
// 申请一个默认的最大容量的内存空间
l.data = (int *)malloc(MAX_SIZE * sizeof(int));
// 设置最大容量
l.maxSize = MAX_SIZE; // 初始化,里面没有数据所以长度为0
l.length = 0;
for(int i = 0; i < l.length; i++) {
// 将申请的内存空间中的值设为0
// 虽然C语言的基本数据类型又默认值,但是刚刚申请的内存空间中可能存在有脏数据,所以进行一下初始化
// 有兴趣的小伙伴可以尝试一下申请一个内存空间然后直接打印里面的值
l.data[i] = 0;
}
// 返回刚刚声明并初始化好的顺序表
return l;
}
- 扩展顺序表的最大容量
/**
* 扩展顺序表的最大容量
* @param &l 顺序表
* @param length 要扩展的长度
*/
bool extend(SeqList &l, int length) {
// 声明一个临时指针指向线性表数据
int *temp = l.data;
// 申请一片连续的内存空间给线性表
l.data = (int *)malloc((l.maxSize + length) * sizeof(int));
for(int i = 0; i < l.length; i++) {
// 将临时指针指向的位置的数据赋值给新的内存空间
l.data[i] = temp[i];
}
// 将最大容量进行重新赋值
l.maxSize += length;
// 将临时指针指向的内存空间进行释放
free(temp);
// 扩容完成返回
return true;
}
- 顺序表的长度和最大容量比较,可以最为共用方法进行使用,以免在代码中出现大量重复代码
/**
* 长度和最大容量比较
* @param l 顺序表
*/
int seqLengthEqualMaxSize(SeqList l) {
// 获取顺序表长度
int length = l.length;
// 获取顺序表最大容量
int maxSize = l.maxSize;
if(length == maxSize) {
return 0;
}
if(length < maxSize) {
return 1;
}
if(length > maxSize) {
return -1;
}
}
- 在最后的位置进行插入
/**
* 插入到最后一个
* @param &l 顺序表
* @param data 要插入的数据
*/
bool addToLast(SeqList &l, int data) {
// 先判断长度和最大容量的大小关系
// 长度大于或者等于最大容量则不进行插入,当然长度大于最大容量的情况可能不存在
int result = seqLengthEqualMaxSize(l);
if(result == 0 || result == -1) {
return false;
}
// 这里要注意长度是顺序表有多少个数据从一开始,而数组下标是从0开始
// 所以最后一个元素的下标是length - 1,所以插入到的最后一个元素的下标应该是当前的length
// 进行赋值
l.data[l.length] = data;
// 复制完成后将顺序表的长度加一
l.length ++;
// 插入成功
return true;
}
- 插入到顺序表的第一个
/**
* 插入到第一个
* @param &l 顺序表
* @param data 要插入的数据
*/
bool addToFirst(SeqList &l, int data) {
// 和插入到最后一个一样先判断长度和最大容量的大小关系
int result = seqLengthEqualMaxSize(l);
if(result == 0 || result == -1) {
return false;
}
// 将顺序表的每个元素往后移一个
for(int i = l.length - 1; i >= 0; i--) {
l.data[i + 1] = l.data[i];
}
// 将顺序表第一个元素,也就是下表为0的元素进行赋值
l.data[0] = data;
// 长度加一
l.length ++;
// 插入成功
return true;
}
- 按照给出的位置插入
/**
* 添加到相应的位置
* @param &l 顺序表
* @patam data 要添加的数据
* @patam index 元素下标
*/
bool addToIndex(SeqList &l, int data, int index) {
int result = seqLengthEqualMaxSize(l);
// 除了之前说过的长度和最大容量的关系外这里多了个传入的下标和都之间的关系
// 因为前面说了length - 1就是最后一个元素的下标,所以传入的下标最大值也就是length
if(result == 0 || result == -1 || index > l.length) {
return false;
}
// 如果传入的下标是0直接调用添加到第一个的方法
if(index == 0) {
addToFirst(l, data);
return true;
}
// 传入的下标和当前的长度相等则证明就是要想最后的位置插入数据
if(index == l.length) {
addToLast(l, data);
return true;
}
// 如果是向其他位置插入数据的话则需要将这个下标及之后的所有元素向后移一位
for(int i = l.length - 1; i >= index; i--) {
l.data[i + 1] = l.data[i];
}
// 赋值
l.data[index] = data;
// 长度加一
l.length++;
// 插入成功
return true;
}
- 删除最后一个元素
/**
* 删除最后一个元素
* @param &l 顺序表
*/
bool removeToLast(SeqList &l) {
// 如果长度小于等于零则证明这个顺序表里面还没有数据,不执行删除操作
if(l.length <= 0) {
return false;
}
// 将最后一个元素置为0
l.data[l.length - 1] = 0;
// 长度减一
// 这里要说一下,就是最后一个元素置零之后长度是必须要减一的因为果不减的话那么最后一个元素的值就变成0了
// 而有些时候0是有意义的
// 还有就是可以不把最后一位置零,但是长度是必须减一的
//因为遍历的时候是按照长度来遍历的,长度减一之后就遍历不到了
// 而且如果想要将最后一位置零的话一定要在长度减一之前,不然置零的就是删除之后的最后一个元素
l.length--;
// 删除成功
return true;
}
- 删除第一个元素
/**
* 删除第一个元素
* @param &l 顺序表
*/
bool removeToFirst(SeqList &l) {
// 和删除最后一个一样
if(l.length <= 0) {
return false;
}
// 将所有元素都向前移动一位
for(int i = 0; i < l.length - 1; i++) {
l.data[i] = l.data[i + 1];
}
// 最后一位置零
l.data[l.length - 1] = 0;
// 同样最后一位可以不置零但是长度一定要减一
l.length--;
// 删除成功
return true;
}
- 删除指定位置的元素
/**
* 删除相应位置的元素
* @param &l 顺序表
* @patam index 元素下标
*/
bool removeToIndex(SeqList &l, int index) {
// 和添加元素的一样逻辑
if(index < 0 || index >= l.length || index > l.length) {
return false;
}
// 删除第一个
if(index == 0) {
removeToFirst(l);
return true;
}
// 删除最后一个
if(index == l.length - 1) {
removeToLast(l);
return true;
}
// 将指定位置及之后的所有元素向前移动一位
for(int i = index; i < l.length - 1; i++) {
l.data[i] = l.data[i + 1];
}
// 最后一位置零
l.data[l.length - 1] = 0;
// 同样可以不置零但必须长度减一
l.length--;
// 删除成功
return true;
}
注:上面的添加到第一个和删除第一个的方法其实是可以省略的,因为在根据位置插入删除的时候他们的时间复杂度都是O(n),而删除个添加到最后一个的时间复杂度是O(1)。当然了可以将添加删除的三个方法整合成一个方法,但是有的时候调用者可能搞不清下标,所以提供了插入、删除第一个和最后一个的方法,也算是提升了一下代码的便捷性把。
纯纯小白码农一枚,自学考研数据结构,如有错误和表达不对的地方,欢迎师哥师姐大佬指正