C语言顺序表源码

简介: 顺序表源码

顺序表源码:

SeqList.h文件

#pragma once//防止重复调用/包含#include<stdio.h>#include<stdlib.h>#include<assert.h>//动态顺序表 --按需扩空间typedefintSLDataType;     //为方便维护修改数据类型,重定义顺序表的数据类型typedefstructSeqList//多个数据定义为结构体,{
SLDataType*a;          //想到动态开辟内存函数malloc,定义一个指针,指向动态开辟的数组intsize;               //有效数据个数intcapacity;           //空间容量大小,满了relloc扩容}SL;//typedef重定义voidSLPrint(SL*ps);           //打印函数的声明//void SeqListInit(SL s);       //全称voidSLInit(SL*ps);            //定义一个顺序表voidSLDestroy(SL*ps);         //释放动态开辟的内存voidSLCheckCapacity(SL*ps);   //检查,扩容//尾插尾删voidSLPushBack(SL*ps, SLDataTypex);
voidSLPopBack(SL*ps);               
//头插头删voidSLPushFront(SL*ps, SLDataTypex);
voidSLPopFront(SL*ps);              
//在pos位置插入数据voidSLInsert(SL*ps, intpos, SLDataTypex);
//删除pos位置数据,删除指定位置的数据voidSLErase(SL*ps, intpos);
////查找数据,为实现删除指定数据//int SLFind(SL* ps, SLDataType x);//查找改进,针对有重复数据intSLFind(SL*ps, SLDataTypex, intbegin);

SeqList.c文件

#include"SeqList.h"//引用头文件voidSLInit(SL*ps)
{
assert(ps);
//初始化ps->a=NULL;//结构体指针用->ps->size=0;
ps->capacity=0;
}
//打印函数voidSLPrint(SL*ps)
{
assert(ps);
for (inti=0; i<ps->size; ++i)
    {
printf("%d ", ps->a[i]);
    }
printf("\n");
}
voidSLDestroy(SL*ps)
{
//if(ps->a !=NULL)assert(ps);
if (ps->a)         //为真说明内存开辟成功,需要释放置空    {
free(ps->a);   //释放,free报错往往是越界,或者是释放的地方不对,一般free的时候才会检查越界ps->a=NULL;  //置空ps->size=ps->capacity=0;//顺便修改他俩的值    }
}
voidSLCheckCapacity(SL*ps)//检查,扩容{
assert(ps);
//插入前得开空间,判断空间是否满,否则涉及到越界问题//判断size和capacity是否相等,相等则满,或者还没开辟空间,因为开始时都初始化为0if (ps->size==ps->capacity)
    {
intnewCapacity=ps->capacity==0?4 : ps->capacity*2;//如果是0还没开辟空间,如果不是就直接扩为2倍//ps->a = (SLDataType*)realloc(ps->a, newCapacity * sizeof(SLDataType));//扩容  ,realloc后面的参数是大小,前面的是需要扩容的空间//需要接收地址,因为relloc返回的是新开空间的地址SLDataType*tmp= (SLDataType*)realloc(ps->a, newCapacity*sizeof(SLDataType));//扩容  ,realloc后面的参数是大小,前面的是需要扩容的空间//需要用临时变量tmp接收地址,因为relloc返回的是新开空间的地址if (tmp==NULL)//判断扩容是否成功        {
perror("relloc fail");
exit(-1);//异常终止程序,0代表正常终止        }
ps->a=tmp;
ps->capacity=newCapacity;
    }
}
//尾插O(1)voidSLPushBack(SL*ps, SLDataTypex)
{
/*assert(ps);SLCheckCapacity(ps);ps->a[ps->size] = x;ps->size++;*/SLInsert(ps, ps->size, x);//复用}
//尾删voidSLPopBack(SL*ps)
{
//温柔的检查/*if (ps->size == 0){return;}*///暴力的检查(断言)assert(ps->size>0);//会直接报错,为真继续走,为假结束//ps->a[ps->size - 1] = 0;//将最后一个数据改为0,再size--,意义不大,因为print是以size为基础的,只会访问size前面的数据,再插入数据会将无效数据直接覆盖ps->size--;
//SLErase(ps, ps->size - 1);//复用}
//头插O(N)voidSLPushFront(SL*ps, SLDataTypex)
{
//assert(ps);//SLCheckCapacity(ps);////挪动数据//int end = ps->size - 1;//size-1是最后一个元素的下标//while (end >= 0)//{//  ps->a[end + 1] = ps->a[end];//  --end;//}//ps->a[0] = x;//ps->size++;SLInsert(ps, 0, x);//复用}
//头删voidSLPopFront(SL*ps)
{
/*assert(ps);assert(ps->size>0);int begin = 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}ps->size--;*/SLErase(ps, 0);//复用}
//在pos位置插入数据voidSLInsert(SL*ps, intpos, SLDataTypex)
{
assert(ps);
assert(pos>=0);
assert(pos<=ps->size);//必须是连续存储SLCheckCapacity(ps);//考虑到后面空间不够可能越界intend=ps->size-1;
while (end>=pos)
    {
ps->a[end+1] =ps->a[end];
end--;
    }
ps->a[pos] =x;
ps->size++;
}
//删除pos位置数据voidSLErase(SL*ps, intpos)
{
assert(ps);
assert(pos>=0);
assert(pos<ps->size);
//assert(ps->size > 0);//挪动数据覆盖intbegin=pos+1;
while (begin<ps->size)
    {
ps->a[begin-1] =ps->a[begin];
begin++;
    }
ps->size--;
}
////查找//int SLFind(SL* ps, SLDataType x)//{//  assert(ps);//  for (int i = 0; i < ps->size; i++)//  {//      if (ps->a[i] == x)//      {//          return i;//      }//  }//  return -1;//}//查找改进,针对有重复数据intSLFind(SL*ps, SLDataTypex,intbegin)
{
assert(ps);
for (inti=begin; i<ps->size; i++)
    {
if (ps->a[i] ==x)
        {
returni;
        }
    }
return-1;
}

test.c文件

在插入菜单前,main函数中调用的测试函数可以根据需要进行修改。

#define _CRT_SECURE_NO_WARNINGS 1#include "SeqList.h"voidTestSeqList1()
{
SLsl;//定义顺序表的结构SLInit(&sl);//初始化,传给了SeqList.c中的函数,实参,传给形参,形参是实参的临时拷贝SLPushBack(&sl, 1);
SLPushBack(&sl, 2);
SLPushBack(&sl, 3);
SLPushBack(&sl, 4);
SLPushBack(&sl, 5);
SLPushBack(&sl, 5);
SLPushBack(&sl, 5);
SLPushBack(&sl, 5);
SLPushBack(&sl, 5);//插入了9个数据,扩了两次容SLPrint(&sl);
SLDestroy(&sl);
}
voidTestSeqList2()
{
SLsl;//定义顺序表的结构SLInit(&sl);//初始化,传给了SeqList.c中的函数,实参,传给形参,形参是实参的临时拷贝SLPushBack(&sl, 1);
SLPushBack(&sl, 2);
SLPushBack(&sl, 3);
SLPushBack(&sl, 4);
SLPrint(&sl);
SLPopBack(&sl);
SLPrint(&sl);
SLPopBack(&sl);
SLPrint(&sl);
SLPopBack(&sl);
SLPopBack(&sl);
SLPopBack(&sl);
SLPopBack(&sl);
//SLPopBack(&sl);//越界调试,size--会导致size出现负数,后面如果再尾插,插入到了不属于自己的空间,就是越界访问SLPrint(&sl);
SLPushBack(&sl, 3);
SLPushBack(&sl, 4);
SLDestroy(&sl);//去掉不报错}
voidTestSeqList3()
{
SLsl;//定义顺序表的结构SLInit(&sl);//初始化,传给了SeqList.c中的函数,实参,传给形参,形参是实参的临时拷贝SLPushFront(&sl, 1);
SLPushFront(&sl, 2);
SLPushFront(&sl, 3);
SLPushFront(&sl, 4);
SLPrint(&sl);
SLPopFront(&sl);
SLPopFront(&sl);
SLPopFront(&sl);
SLPopFront(&sl);
SLPopFront(&sl);//四个数据删除五次size为空,运行正常,可能没测试到位SLPushBack(&sl, 10);//这时就出现了问题,发生了越界,free会报错SLPrint(&sl);
SLDestroy(&sl);
}
voidTestSeqList4()
{
SLsl;//定义顺序表的结构SLInit(&sl);//初始化,传给了SeqList.c中的函数,实参,传给形参,形参是实参的临时拷贝SLPushBack(&sl, 1);
SLPushBack(&sl, 2);
SLPushBack(&sl, 3);
SLPushBack(&sl, 4);
SLPrint(&sl);
SLInsert(&sl, 2, 20);//第二个位置插入20SLPrint(&sl);
SLInsert(&sl, 5, 500);//相当于尾插,需要考虑复用SLPrint(&sl);
SLInsert(&sl, 0, 100);//相当于头插,需要考虑复用SLPrint(&sl);
SLDestroy(&sl);
}
voidTestSeqList5()
{
SLsl;//定义顺序表的结构SLInit(&sl);//初始化,传给了SeqList.c中的函数,实参,传给形参,形参是实参的临时拷贝SLPushBack(&sl, 1);
SLPushBack(&sl, 2);
SLPushBack(&sl, 3);
SLPushBack(&sl, 4);
SLPrint(&sl);
SLErase(&sl, 2);//删除下标为2的值SLPrint(&sl);
SLErase(&sl, 2);//删除下标为2的值SLPrint(&sl);
SLErase(&sl, 0);//删除下标为2的值SLPrint(&sl);
SLDestroy(&sl);
}
voidTestSeqList6()
{
SLsl;//定义顺序表的结构SLInit(&sl);//初始化,传给了SeqList.c中的函数,实参,传给形参,形参是实参的临时拷贝SLPushBack(&sl, 1);
SLPushBack(&sl, 2);
SLPushBack(&sl, 3);
SLPushBack(&sl, 4);
SLPushBack(&sl, 5);
SLPushBack(&sl, 7);
SLPushBack(&sl, 8);
SLPushBack(&sl, 5);
SLPrint(&sl);
/*int pos = SLFind(&sl, 5);if (pos != -1){SLErase(&sl, pos);}SLPrint(&sl);*/intpos=SLFind(&sl, 4,0);//从0开始查找if (pos!=-1)
    {
SLErase(&sl, pos);
    }
SLPrint(&sl);
//删除所有的5pos=SLFind(&sl, 5, 0);
while (pos!=-1)
    {
SLErase(&sl, pos);
pos=SLFind(&sl, 5, pos);//从删除5的位置继续往后找    }
SLPrint(&sl);
SLDestroy(&sl);
}
//int main()//{//  //TestSeqList1();//  //TestSeqList2();//  //TestSeqList3();//  //TestSeqList4();//  //TestSeqList5();//  TestSeqList6();////  //int* p1 = malloc(4);//  //int* p2 = realloc(p1, 20);//  //int* p3 = realloc(p2, 2000);//realloc原地扩容和异地扩容的演示////  ////越界读基本不会被检查出来//  //int a[10] = { 0 };//  //printf("%d\n", a[10]);//  //printf("%d\n", a[11]);//  ////  ////越界写,可能会被检查出来//  ////a[10] = 0;//检查出来//  //a[11] = 0;//未检查出来//  //////  return 0;//}//菜单voidmenu()
{
printf("********************************************\n");
printf("1、尾插数据 2、尾删数据\n");
printf("3、头插数据 2、头删数据\n");
printf("5、打印数据 -1、退出\n");
printf("********************************************\n");
}
intmain()
{
SLs;//定义顺序表SLInit(&s);//初始化intval=0;
intoption=0;
do    {
menu();
printf("请输入你的操作:>");
scanf("%d", &option);
switch (option)
        {
case1:
printf("请依次输入你要尾插的数据,以-1结束");
scanf("%d", &val);
while (val!=-1)
            {
SLPushBack(&s, val);
scanf("%d", &val);
            }
break;
case2:
SLPopFront(&s);
break;
case3:
break;
case4:
break;
case5:
SLPrint(&s);
break;
default:
break;
        }
    }while (option!=-1);
SLDestroy(&s);
return0;
}


结语:

这里本章内容就介绍完了, 希望以上内容对大家有所帮助👀,如有不足望指出🙏

前路漫漫!努力变强💪💪 吧!!

相关文章
|
19天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
97 9
|
1月前
|
存储 C语言
【C语言篇】深入理解指针3(附转移表源码)
【C语言篇】深入理解指针3(附转移表源码)
37 1
|
18天前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
60 16
|
13天前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
56 8
|
13天前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
46 7
|
11天前
|
C语言 Windows
C语言课设项目之2048游戏源码
C语言课设项目之2048游戏源码,可作为课程设计项目参考,代码有详细的注释,另外编译可运行文件也已经打包,windows电脑双击即可运行效果
24 1
|
18天前
|
C语言
【数据结构】二叉树(c语言)(附源码)
本文介绍了如何使用链式结构实现二叉树的基本功能,包括前序、中序、后序和层序遍历,统计节点个数和树的高度,查找节点,判断是否为完全二叉树,以及销毁二叉树。通过手动创建一棵二叉树,详细讲解了每个功能的实现方法和代码示例,帮助读者深入理解递归和数据结构的应用。
66 8
|
20天前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
48 4
|
22天前
|
存储 C语言
【数据结构】顺序表(c语言实现)(附源码)
本文介绍了线性表和顺序表的基本概念及其实现。线性表是一种有限序列,常见的线性表有顺序表、链表、栈、队列等。顺序表是一种基于连续内存地址存储数据的数据结构,其底层逻辑是数组。文章详细讲解了静态顺序表和动态顺序表的区别,并重点介绍了动态顺序表的实现,包括初始化、销毁、打印、增删查改等操作。最后,文章总结了顺序表的时间复杂度和局限性,并预告了后续关于链表的内容。
56 3
|
1月前
|
存储 C语言
探索C语言数据结构:利用顺序表完成通讯录的实现
本文介绍了如何使用C语言中的顺序表数据结构实现一个简单的通讯录,包括初始化、添加、删除、查找和保存联系人信息的操作,以及自定义结构体用于存储联系人详细信息。
20 2