目录
后记:●由于作者水平有限,文章难免存在谬误之处,敬请读者斧正,俚语成篇,恳望指教!
详细实现链接:
<顺序表>《数据结构(C语言版)》
顺序表功能实现(增删查改)《数据结构(C语言版)》
1.线性表
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
2.顺序表实现
2.1概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。顺序表一般可以分为:1. 静态顺序表:使用定长数组存储。2. 动态顺序表:使用动态开辟的数组存储。
2.2 接口实现:
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。
静态顺序表测试示例:
SeqList.h:
//#pragma once #include<stdio.h> #include<string.h> /*#ifndef __SEQLIST__H__ #define __SEQLIST__H__ 静态顺序表 //struct SeqList //{ // int a[10]; // int size; //}; //缺点: //1.数组大小定长,不利于变换 //2.类型固定,不利于变换 //静态顺序表 #define N 100 typedef int SQDataType; //typedef char SQDataType; //可以通过在此处改变类型,实现更换。即“一改全改”,增强程序的可维护性 struct SeqList { SQDataType a[N]; int size; }; void SeqListInit(struct SeqList sl); #endif*/ 静态顺序表 //struct SeqList //{ // int a[10]; // int size; //}; //缺点: //1.数组大小定长,不利于变换 //2.类型固定,不利于变换 写法1: 静态顺序表 //#define MAX_SIZE 100 //typedef int SQDataType; typedef char SQDataType; //可以通过在此处改变类型,实现更换。即“一改全改”,增强程序的可维护性 // //struct SeqList //{ // SQDataType a[MAX_SIZE]; // int size; //}; // //void SeqListInit(struct SeqList s); // 写法2: 静态顺序表 //#define MAX_SIZE 100 //typedef int SQDataType; typedef char SQDataType; //可以通过在此处改变类型,实现更换。即“一改全改”,增强程序的可维护性 // //struct SeqList //{ // SQDataType a[MAX_SIZE]; // int size; //}; // //typedef struct SeqList SL; //void SeqListInit(SL s); //写法3: //静态顺序表 #define MAX_SIZE 100 typedef int SQDataType; //typedef char SQDataType; //可以通过在此处改变类型,实现更换。即“一改全改”,增强程序的可维护性 typedef struct SeqList { SQDataType a[MAX_SIZE]; //顺序表存储方式——数组 int size; //顺序表已使用容量 }SL; //静态顺序表缺点: //1.数组大小定长,不利于变换 //2.类型固定,不利于变换 //即:给少了不够用,给多了浪费,不能灵活控制 //顺序表初始化 //void SeqListInit(SL s); void SeqListInit(SL* ps); //顺序表尾插数据 void SeqListPushBack(SL* ps, SQDataType x); //顺序表头插数据 void SeqListPushFront(SL* ps, SQDataType x); //顺序表尾删数据 void SeqListPopBack(SL* ps); //顺序表头删数据 void SeqListPopFront(SL* ps); //打印函数 void Print(SL* ps);
SeqList.c:
#include"SeqList.h" //顺序表初始化 void SeqListInit(SL* ps) { memset(ps->a,0,sizeof(SQDataType) * MAX_SIZE); //将数组a按字节初始化 ps->size = 0; } //打印函数 void Print(SL* ps) { for (int i = 0; i < ps->size; i++) { printf("%d ", ps->a[i]); } printf("\n"); } //顺序表尾插数据 void SeqListPushBack(SL* ps, SQDataType x) { if (ps->size >= MAX_SIZE) { printf("SeqList is FULL!\n"); return; } ps->a[ps->size] = x; ps->size++; //size++在后面多加一次,是为区分数组下标与个数不同步,数组下标从0开始,而size是已使用容量个数 } //顺序表头插数据 void SeqListPushFront(SL* ps, SQDataType x){} //顺序表尾删数据 void SeqListPopBack(SL* ps){} //顺序表头删数据 void SeqListPopFront(SL* ps){}
Test.c:
#include "SeqList.h" void TestSeqList1() { SL sl; SeqListInit(&sl); //实参传地址给形参,形参使用指针接收 SeqListPushBack(&sl,2); SeqListPushBack(&sl,0); SeqListPushBack(&sl,2); SeqListPushBack(&sl,2); Print(&sl); } int main() { TestSeqList1(); return 0; }
动态顺序表:
SeqList.h:
#pragma once #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #include<stdlib.h> #include<assert.h> //静态顺序表 ///*#ifndef __SEQLIST__H__ //#define __SEQLIST__H__ // // //静态顺序表 struct SeqList { int a[10]; int size; }; 缺点: 1.数组大小定长,不利于变换 2.类型固定,不利于变换 // 静态顺序表 //#define N 100 //typedef int SQDataType; typedef char SQDataType; //可以通过在此处改变类型,实现更换。即“一改全改”,增强程序的可维护性 // //struct SeqList //{ // SQDataType a[N]; // int size; //}; // //void SeqListInit(struct SeqList sl); // //#endif*/ // // // //静态顺序表 struct SeqList { int a[10]; int size; }; 缺点: 1.数组大小定长,不利于变换 2.类型固定,不利于变换 // //写法1: //静态顺序表 #define MAX_SIZE 100 typedef int SQDataType; //typedef char SQDataType; //可以通过在此处改变类型,实现更换。即“一改全改”,增强程序的可维护性 struct SeqList { SQDataType a[MAX_SIZE]; int size; }; void SeqListInit(struct SeqList s); //写法2: //静态顺序表 #define MAX_SIZE 100 typedef int SQDataType; //typedef char SQDataType; //可以通过在此处改变类型,实现更换。即“一改全改”,增强程序的可维护性 struct SeqList { SQDataType a[MAX_SIZE]; int size; }; typedef struct SeqList SL; void SeqListInit(SL s); // 写法3: 静态顺序表 //#define MAX_SIZE 100 // //typedef int SQDataType; typedef char SQDataType; //可以通过在此处改变类型,实现更换。即“一改全改”,增强程序的可维护性 // //typedef struct SeqList //{ // SQDataType a[MAX_SIZE]; //顺序表存储方式——数组 // int size; //顺序表已使用容量 //}SL; 静态顺序表缺点: 1.数组大小定长,不利于变换 2.类型固定,不利于变换 即:给少了不够用,给多了浪费,不能灵活控制 // // // // // 顺序表初始化 void SeqListInit(SL s); //void SeqListInit(SL* ps); // 顺序表尾插数据 //void SeqListPushBack(SL* ps, SQDataType x); 顺序表头插数据 //void SeqListPushFront(SL* ps, SQDataType x); 顺序表尾删数据 //void SeqListPopBack(SL* ps); 顺序表头删数据 //void SeqListPopFront(SL* ps); 打印函数 //void Print(SL* ps); // //动态顺序表 typedef int SQDataType; typedef struct SeqList { SQDataType* a; //顺序表存储方式——数组 int size; //顺序表已使用容量 int capacity; //顺序表总容量 }SL; //顺序表初始化 //void SeqListInit(SL s); void SeqListInit(SL* ps); //顺序表打印 void SeqLisPrint(SL* ps); //顺序表尾插数据 void SeqListPushBack(SL* ps, SQDataType x); //顺序表头插数据 void SeqListPushFront(SL* ps, SQDataType x); //顺序表尾删数据 void SeqListPopBack(SL* ps); //顺序表头删数据 void SeqListPopFront(SL* ps); //指定位置插入数据 void SeqListInsert(SL* ps, int pos, SQDataType x); //指定位置删除数据 void SeqListErase(SL* ps, int pos); //销毁、释放内存空间 void SeqListDestroy(SL* ps); //顺序表查找 int SeqListFind(SL* ps, SQDataType x); //顺序表修改 void SeqListModify(SL* ps, int pos,SQDataType x);
SeqList.c:
#include"SeqList.h" //顺序表初始化 void SeqListInit(SL* ps) { ps->a = NULL; ps->size = 0; ps->capacity = 0; } //顺序表打印 void SeqLisPrint(SL* ps) { for (int i = 0; i < ps->size; i++) { printf("%d ", ps->a[i]); } printf("\n"); } //封装一个检查增容函数 void SeqListCheckCapacity(SL* ps) { //空间满了,就扩容 if (ps->size == ps->capacity) { int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2; //防止最初capacity为0,ps->capacity * 2之后仍为0 SQDataType* tmp = (SQDataType*)realloc(ps->a, newcapacity * sizeof(SQDataType)); if (tmp == NULL) { printf("扩容失败!\n"); exit(-1); } else { ps->a = tmp; ps->capacity = newcapacity; } } } 1.顺序表尾插数据 //void SeqListPushBack(SL* ps, SQDataType x) //{ // //1.自己实现检查并增容 // 空间满了,就扩容 // //if (ps->size == ps->capacity) // //{ // // int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2; //防止最初capacity为0,ps->capacity * 2之后仍为0 // // SQDataType* tmp = (SQDataType*)realloc(ps->a, newcapacity * sizeof(SQDataType)); // // if (tmp == NULL) // // { // // printf("扩容失败!\n"); // // exit(-1); // // } // // else // // { // // ps->a = tmp; // // ps->capacity = newcapacity; // // } // //} // //2.附用SeqListCheckCapacity(SL* ps)函数 // SeqListCheckCapacity(ps); // ps->a[ps->size] = x; // ps->size++; //size++在后面多加一次,是为了区分数组下标与个数不同步,数组下标从0开始,而size是已使用容量个数 // //} //2.顺序表尾插数据——附用SeqListInsert void SeqListPushBack(SL* ps, SQDataType x) { assert(ps); SeqListInsert(ps, ps->size, x); } 1.顺序表头插数据 //void SeqListPushFront(SL* ps, SQDataType x) //{ // SeqListCheckCapacity(ps); // int end = ps->size - 1; // while (end >= 0) // { // ps->a[end + 1] = ps->a[end]; // --end; // } // ps->a[0] = x; // ps->size++; //} //2.顺序表头插数据——附用SeqListInsert void SeqListPushFront(SL* ps, SQDataType x) { assert(ps); SeqListInsert(ps, 0, x); } 1.顺序表尾删数据 //void SeqListPopBack(SL* ps) //{ // assert(ps->size > 0); // ps->size--; //} //2.顺序表尾删数据——附用SeqListErase void SeqListPopBack(SL* ps) { assert(ps); SeqListErase(ps, ps->size - 1); } 1.顺序表头删数据 //void SeqListPopFront(SL* ps) //{ // assert(ps->size > 0); // int start = 1; // while (start < ps->size) // { // ps->a[start - 1] = ps->a[start]; // ++start; // } // ps->size--; //} //2.顺序表头删数据——附用SeqListErase void SeqListPopFront(SL* ps) { assert(ps); SeqListErase(ps, 0); } //指定位置插入数据 void SeqListInsert(SL* ps, int pos, SQDataType x) { assert(pos <= ps->size); SeqListCheckCapacity(ps); int end = ps->size - 1; while (end >= pos) { ps->a[end + 1] = ps->a[end]; --end; } ps->a[pos] = x; ps->size++; } //指定位置删除数据 void SeqListErase(SL* ps, int pos) { assert(ps); assert(pos < ps->size); int start = pos + 1; while (start < ps->size) { ps->a[start - 1] = ps->a[start]; ++start; } ps->size--; } //销毁、释放内存空间 void SeqListDestroy(SL* ps) { assert(ps); free(ps->a); ps->a = NULL; ps->capacity = ps->size = 0; } //顺序表查找 int SeqListFind(SL* ps, SQDataType x) { assert(ps); for (int i = 0; i < ps->size; i++) { if (ps->a[i] == x) { return i; } } return -1; } //顺序表修改 void SeqListModify(SL* ps, int pos, SQDataType x) { assert(ps); assert(pos < ps->size); ps->a[pos] = x; }
Test.c:
#include "SeqList.h" void TestSeqList1() { SL sl; SeqListInit(&sl); //实参传地址给形参,形参使用指针接收 SeqListPushBack(&sl,2); SeqListPushBack(&sl,0); SeqListPushBack(&sl,2); SeqListPushBack(&sl,2); SeqListPushBack(&sl,0); SeqListPushBack(&sl,8); SeqListPushBack(&sl,2); SeqListPushBack(&sl,7); SeqLisPrint(&sl); } void TestSeqList2() { SL sl; SeqListInit(&sl); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 0); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 0); SeqListPushFront(&sl, 8); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 7); SeqLisPrint(&sl); } void TestSeqList3() { SL sl; SeqListInit(&sl); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 0); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 0); SeqListPushFront(&sl, 8); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 7); SeqLisPrint(&sl); SeqListPopBack(&sl); SeqLisPrint(&sl); SeqListPopFront(&sl); SeqLisPrint(&sl); } void TestSeqList4() { SL sl; SeqListInit(&sl); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 0); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 0); SeqListPushFront(&sl, 8); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 7); SeqLisPrint(&sl); SeqListPopBack(&sl); SeqLisPrint(&sl); SeqListPopFront(&sl); SeqLisPrint(&sl); } void TestSeqList5() { SL sl; SeqListInit(&sl); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 0); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 0); SeqListPushFront(&sl, 8); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 7); SeqLisPrint(&sl); SeqListInsert(&sl, 5, 1); SeqLisPrint(&sl); SeqListInsert(&sl, 7, 1); SeqLisPrint(&sl); } void TestSeqList6() { SL sl; SeqListInit(&sl); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 0); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 0); SeqListPushFront(&sl, 8); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 7); SeqLisPrint(&sl); SeqListInsert(&sl, 5, 10); SeqLisPrint(&sl); SeqListErase(&sl, 1); SeqLisPrint(&sl); } void TestSeqList7() { SL sl; SeqListInit(&sl); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 0); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 0); SeqListPushFront(&sl, 8); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 7); SeqLisPrint(&sl); SeqListInsert(&sl, 5, 10); SeqLisPrint(&sl); SeqListErase(&sl, 1); SeqLisPrint(&sl); SeqListDestroy(&sl); } void TestSeqList8() { SL sl; SeqListInit(&sl); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 0); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 0); SeqListPushFront(&sl, 8); SeqListPushFront(&sl, 2); SeqListPushFront(&sl, 7); SeqLisPrint(&sl); //查找 int pos = SeqListFind(&sl, 0); if (pos != -1) { printf("查找下标:%d \n", pos); } SeqListModify(&sl, 6,9); SeqLisPrint(&sl); SeqListDestroy(&sl); } int main() { TestSeqList1(); TestSeqList2(); TestSeqList3(); TestSeqList4(); TestSeqList5(); TestSeqList6(); TestSeqList7(); TestSeqList8(); return 0; } 菜单版 //void menu() //{ // printf("****************************\n"); // printf("1.头插数据 2.尾插数据\n"); // printf("3.头删数据 4.尾删数据\n"); // printf("5.按值查找数据 6.修改数据\n"); // printf("7.打印数据 -1.退出\n"); // printf("****************************\n"); // printf("请输入你的操作选项:\n"); //} //int main() //{ // SL s; // SeqListInit(&s); // int option = 0; // int pos = 0; // int x = 0; // // while (option != -1) // { // menu(); // scanf("%d", &option); // switch (option) // { // // case 1: // printf("请输入你要头插的数据,以-1结束\n"); // do { // scanf("%d", &x); // if (x != -1) // { // SeqListPushFront(&s, x); // } // } while (x != -1); // break; // case 2: // printf("请输入你要尾插的数据,以-1结束\n"); // do { // scanf("%d", &x); // if (x != -1) // { // SeqListPushBack(&s, x); // } // } while (x != -1); // // break; // case 3: // SeqListPopFront(&s); // printf("头删完成!\n"); // // // break; // case 4: // SeqListPopBack(&s); // printf("尾删完成!\n"); // // break; // case 5: // printf("请输入你要查找的数据:\n"); // scanf("%d", &x); // int post = SeqListFind(&s, x); // if (post != -1) // { // printf("查找下标:%d \n", post); // } // break; // case 6: // printf("请输入你要修改的数据:\n"); // scanf("%d", &x); // SeqListModify(&s, pos, x); // break; // case 7: // SeqLisPrint(&s); // // break; // default: // break; // } // } // SeqListDestroy(&s); // return 0; //}