1 -> 线性表
线性表(linear list)是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串……
线性表在逻辑上是线性结构,也就是说它是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
2 -> 顺序表
2.1 -> 概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删改查。
顺序表一般可以分为:
1. 静态顺序表:使用定长数组存储元素。
2. 动态顺序表:使用动态开辟的数组存储。
2.2 -> 接口声明
静态顺序表只适用于已知需要多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以实现动态顺序表。
#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <assert.h> #include <stdlib.h> // 顺序表的动态存储 typedef int SLDateType; typedef struct SeqList { // 指向动态开辟的数组 SLDateType* a; // 有效数据个数 int size; // 容量空间大小 int capacity; }SL; // 对数据的管理:增删查改 // 顺序表初始化 void SLInit(SL* psl); // 顺序表销毁 void SLDestroy(SL* psl); // 顺序表检查,满则增容 void SLCheckCapacity(SL* psl); // 顺序表打印 void SLPrint(SL* psl); // 顺序表尾插 void SLPushBack(SL* psl, SLDateType x); // 顺序表头插 void SLPushFront(SL* psl, SLDateType x); // 顺序表尾删 void SLPopBack(SL* psl); // 顺序表头删 void SLPopFront(SL* psl); // 顺序表在pos位置插入x void SLInsert(SL* psl, int pos, SLDateType x); // 顺序表删除pos位置的值 void SLErase(SL* psl, int pos); // 顺序表查找,找到返回下标,找不到返回-1 int SLFind(SL* psl, SLDateType x); // 顺序表修改 void SLModify(SL* psl, int pos, SLDateType x);
2.3 -> 接口实现
2.3.1 -> 初始化
// 顺序表初始化 void SLInit(SL* psl) { psl->a = (SLDateType*)malloc(sizeof(SLDateType) * 4); if (psl->a == NULL) { perror("malloc fail"); return; } psl->capacity = 4; psl->size = 0; }
2.3.2 -> 销毁
// 顺序表销毁 void SLDestroy(SL* psl) { free(psl->a); psl->a = NULL; psl->capacity = 0; psl->size = 0; }
2.3.3 -> 检查
// 顺序表检查,满则增容 void SLCheckCapacity(SL* psl) { if (psl->size == psl->capacity) { SLDateType* tmp = (SLDateType*)realloc(psl->a, sizeof(SLDateType) * psl->capacity * 2); if (tmp == NULL) { perror("realloc fail"); return; } psl->a = tmp; psl->capacity *= 2; } }
2.3.4 -> 打印
// 顺序表打印 void SLPrint(SL* psl) { for (int i = 0; i < psl->size; i++) { printf("%d ", psl->a[i]); } printf("\n"); }
2.3.5 -> 尾插
// 顺序表尾插 void SLPushBack(SL* psl, SLDateType x) { SLCheckCapacity(psl); psl->a[psl->size++] = x; //复用 //SLInsert(psl, psl->size - 1, x); }
// 尾插测试 void SLTest1() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushBack(&s, 5); SLPrint(&s); SLDestroy(&s); }
2.3.6 -> 头插
// 顺序表头插 void SLPushFront(SL* psl, SLDateType x) { SLCheckCapacity(psl); int end = psl->size - 1; while (end >= 0) { psl->a[end + 1] = psl->a[end]; --end; } psl->a[0] = x; psl->size++; //复用 //SLInsert(psl, 0, x); }
// 头插测试 void SLTest2() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushFront(&s, 4); SLPushFront(&s, 5); SLPushFront(&s, 6); SLPrint(&s); SLDestroy(&s); }
2.3.7 -> 尾删
// 顺序表尾删 void SLPopBack(SL* psl) { // 暴力的检查 assert(psl->size > 0); // 温柔的检查 /*if (psl->size == 0) return;*/ psl->size--; //复用 //SLErase(psl, psl->size - 1); }
// 尾删测试 void SLTest3() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushFront(&s, 4); SLPushFront(&s, 5); SLPushFront(&s, 6); SLPrint(&s); SLPopBack(&s); SLPopBack(&s); SLPopBack(&s); SLPrint(&s); SLDestroy(&s); }
2.3.8 -> 头删
// 顺序表头删 void SLPopFront(SL* psl) { assert(psl->size > 0); int start = 1; while (psl->a[start] < psl->size) { psl->a[start - 1] = psl->a[start]; start++; } psl->size--; //复用 //SLErase(psl, 0); }
// 头删测试 void SLTest4() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushFront(&s, 4); SLPushFront(&s, 5); SLPushFront(&s, 6); SLPrint(&s); SLPopFront(&s); SLPopFront(&s); SLPopFront(&s); SLPrint(&s); SLDestroy(&s); }
2.3.9 -> 在pos位置插入x
// 顺序表在pos位置插入x // 头插、尾插可复用此 void SLInsert(SL* psl, int pos, SLDateType x) { assert(0 <= pos && pos <= psl->size); SLCheckCapacity(psl); int end = psl->size - 1; while (end >= pos) { psl->a[end + 1] = psl->a[end]; --end; } psl->a[pos] = x; psl->size++; }
// 任意位置插入测试 void SLTest5() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushFront(&s, 4); SLPushFront(&s, 5); SLPushFront(&s, 6); SLPrint(&s); SLInsert(&s, 1, 99); SLInsert(&s, 3, 22); SLPrint(&s); SLDestroy(&s); }
2.3.10 -> 删除pos位置的值
// 顺序表删除pos位置的值 // 头删、尾删可复用此 void SLErase(SL* psl, int pos) { assert(0 <= pos && pos < psl->size); assert(psl->size > 0); int start = pos + 1; while (start < psl->size) { psl->a[start - 1] = psl->a[start]; ++start; } psl->size--; }
// 任意位置删除测试 void SLTest6() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushBack(&s, 5); SLPushBack(&s, 6); SLPrint(&s); SLErase(&s, 2); SLErase(&s, 4); SLPrint(&s); SLDestroy(&s); }
2.3.11 -> 查找
// 顺序表查找 int SLFind(SL* psl, SLDateType x) { for (int i = 0; i < psl->size; i++) { if (psl->a[i] == x) return i; } return -1; }
// 查找测试 void SLTest7() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushBack(&s, 5); SLPushBack(&s, 6); SLPrint(&s); int ans1 = SLFind(&s, 2); int ans2 = SLFind(&s, 6); printf("%d\n%d", ans1, ans2); SLDestroy(&s); }
2.3.12 -> 修改
// 顺序表修改 void SLModify(SL* psl, int pos, SLDateType x) { assert(0 <= pos && pos < psl->size); psl->a[pos] = x; }
// 修改测试 void SLTest8() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushBack(&s, 5); SLPushBack(&s, 6); SLPrint(&s); SLModify(&s, 2, 99); SLModify(&s, 0, 11); SLPrint(&s); SLDestroy(&s); }
3 -> 完整代码
3.1 -> SeqList.h
#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <assert.h> #include <stdlib.h> // 顺序表的动态存储 typedef int SLDateType; typedef struct SeqList { // 指向动态开辟的数组 SLDateType* a; // 有效数据个数 int size; // 容量空间大小 int capacity; }SL; // 对数据的管理:增删查改 // 顺序表初始化 void SLInit(SL* psl); // 顺序表销毁 void SLDestroy(SL* psl); // 顺序表检查,满则增容 void SLCheckCapacity(SL* psl); // 顺序表打印 void SLPrint(SL* psl); // 顺序表尾插 void SLPushBack(SL* psl, SLDateType x); // 顺序表头插 void SLPushFront(SL* psl, SLDateType x); // 顺序表尾删 void SLPopBack(SL* psl); // 顺序表头删 void SLPopFront(SL* psl); // 顺序表在pos位置插入x void SLInsert(SL* psl, int pos, SLDateType x); // 顺序表删除pos位置的值 void SLErase(SL* psl, int pos); // 顺序表查找,找到返回下标,找不到返回-1 int SLFind(SL* psl, SLDateType x); // 顺序表修改 void SLModify(SL* psl, int pos, SLDateType x);
3.2 -> SeqList.c
#include "SeqList.h" // 顺序表初始化 void SLInit(SL* psl) { psl->a = (SLDateType*)malloc(sizeof(SLDateType) * 4); if (psl->a == NULL) { perror("malloc fail"); return; } psl->capacity = 4; psl->size = 0; } // 顺序表销毁 void SLDestroy(SL* psl) { free(psl->a); psl->a = NULL; psl->capacity = 0; psl->size = 0; } // 顺序表检查,满则增容 void SLCheckCapacity(SL* psl) { if (psl->size == psl->capacity) { SLDateType* tmp = (SLDateType*)realloc(psl->a, sizeof(SLDateType) * psl->capacity * 2); if (tmp == NULL) { perror("realloc fail"); return; } psl->a = tmp; psl->capacity *= 2; } } // 顺序表打印 void SLPrint(SL* psl) { for (int i = 0; i < psl->size; i++) { printf("%d ", psl->a[i]); } printf("\n"); } // 顺序表尾插 void SLPushBack(SL* psl, SLDateType x) { SLCheckCapacity(psl); psl->a[psl->size++] = x; //复用 //SLInsert(psl, psl->size - 1, x); } // 顺序表头插 void SLPushFront(SL* psl, SLDateType x) { SLCheckCapacity(psl); int end = psl->size - 1; while (end >= 0) { psl->a[end + 1] = psl->a[end]; --end; } psl->a[0] = x; psl->size++; //复用 //SLInsert(psl, 0, x); } // 顺序表尾删 void SLPopBack(SL* psl) { // 暴力的检查 assert(psl->size > 0); // 温柔的检查 /*if (psl->size == 0) return;*/ psl->size--; //复用 //SLErase(psl, psl->size - 1); } // 顺序表头删 void SLPopFront(SL* psl) { assert(psl->size > 0); int start = 1; while (psl->a[start] < psl->size) { psl->a[start - 1] = psl->a[start]; start++; } psl->size--; //复用 //SLErase(psl, 0); } // 顺序表在pos位置插入x // 头插、尾插可复用此 void SLInsert(SL* psl, int pos, SLDateType x) { assert(0 <= pos && pos <= psl->size); SLCheckCapacity(psl); int end = psl->size - 1; while (end >= pos) { psl->a[end + 1] = psl->a[end]; --end; } psl->a[pos] = x; psl->size++; } // 顺序表删除pos位置的值 // 头删、尾删可复用此 void SLErase(SL* psl, int pos) { assert(0 <= pos && pos < psl->size); assert(psl->size > 0); int start = pos + 1; while (start < psl->size) { psl->a[start - 1] = psl->a[start]; ++start; } psl->size--; } // 顺序表查找 int SLFind(SL* psl, SLDateType x) { for (int i = 0; i < psl->size; i++) { if (psl->a[i] == x) return i; } return -1; } // 顺序表修改 void SLModify(SL* psl, int pos, SLDateType x) { assert(0 <= pos && pos < psl->size); psl->a[pos] = x; }
3.3 -> Test.c
#include "SeqList.h" // 尾插测试 void SLTest1() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushBack(&s, 5); SLPrint(&s); SLDestroy(&s); } // 头插测试 void SLTest2() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushFront(&s, 4); SLPushFront(&s, 5); SLPushFront(&s, 6); SLPrint(&s); SLDestroy(&s); } // 尾删测试 void SLTest3() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushFront(&s, 4); SLPushFront(&s, 5); SLPushFront(&s, 6); SLPrint(&s); SLPopBack(&s); SLPopBack(&s); SLPopBack(&s); SLPrint(&s); SLDestroy(&s); } // 头删测试 void SLTest4() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushFront(&s, 4); SLPushFront(&s, 5); SLPushFront(&s, 6); SLPrint(&s); SLPopFront(&s); SLPopFront(&s); SLPopFront(&s); SLPrint(&s); SLDestroy(&s); } // 任意位置插入测试 void SLTest5() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushFront(&s, 4); SLPushFront(&s, 5); SLPushFront(&s, 6); SLPrint(&s); SLInsert(&s, 1, 99); SLInsert(&s, 3, 22); SLPrint(&s); SLDestroy(&s); } // 任意位置删除测试 void SLTest6() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushBack(&s, 5); SLPushBack(&s, 6); SLPrint(&s); SLErase(&s, 2); SLErase(&s, 4); SLPrint(&s); SLDestroy(&s); } // 查找测试 void SLTest7() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushBack(&s, 5); SLPushBack(&s, 6); SLPrint(&s); int ans1 = SLFind(&s, 2); int ans2 = SLFind(&s, 6); printf("%d\n%d", ans1, ans2); SLDestroy(&s); } // 修改测试 void SLTest8() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushBack(&s, 5); SLPushBack(&s, 6); SLPrint(&s); SLModify(&s, 2, 99); SLModify(&s, 0, 11); SLPrint(&s); SLDestroy(&s); } int main() { return 0; }
感谢各位大佬支持!!!
互三啦!!!