简介
本文主要介绍顺序表的头插、头删、尾插、尾删、查找、插入和删除,提供全部的.c和.h文件,确保使用者直接复制粘贴到编译器上即可直接运行程序。
动态顺序表结构体
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* a;
int size;
int capacity;
}SL;
1.头插功能
思路是先找到数组的最后一个元素,然后把元素一个一个都往后挪一位。最后将要插入的数据x放在数组的头的位置。
void SeqListPushFront(SL* ps, SLDataType 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++;
return;
}
检查是否扩容,是在插入元素时,检查数据个数是否超过了最大容量或者是否需要开辟空间,如果是需要进行空间的开辟或扩容。
void SeqListCheckCapacity(SL* ps)
{
if (ps->capacity == ps->size)
{
int newCapacity = (ps->capacity == 0) ? 4 : ps->capacity * 2;
SLDataType* temp = (SLDataType*)realloc(ps->a, newCapacity * sizeof(SLDataType));
if (NULL == temp)
{
printf("realloc fail!\n");
exit(-1);
}
ps->a = temp;
ps->capacity = newCapacity;
}
return;
}
2.头删功能
思路是先找到数组的第2个元素,然后从第2个数据开始,每个数据往前挪动一位进行数据覆盖。
void SeqListPopFront(SL* ps)
{
assert(ps->size > 0);
int begin = 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
begin++;
}
ps->size--;
return;
}
3.尾插功能
思路是先检查是否需要扩容,然后将需要插入的数据x直接放到数组的尾部即可。
void SeqListPushBack(SL *ps, SLDataType x)
{
SeqListCheckCapacity(ps);
ps->a[ps->size] = x;
ps->size++;
return;
}
4.尾删功能
思路是直接减1有效数据的个数,以此达到删除数组中最后一个元素的目的。
void SeqListPopBack(SL* ps)
{
assert(ps->size > 0);
ps->size--;
return;
}
5.查找功能
思路是遍历顺序表中的数字,找出符合条件的数字并返回对应下标,否则返回-1。
int SeqListFind(SL* ps, SLDataType x)
{
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (ps->a[i] == x)
{
printf("找到x,下标为%d\n", i);
return i;
}
}
printf("x 不在顺序表中!\n");
return -1;
}
6.插入功能
思路是先找到数组的最后位置,然后将数据一个一个往后挪一位。
注意:插入函数可以实现头插功能和尾插功能
头插:SeqListInsert(ps, 0, 10);
尾插:SeqListInsert(ps, ps->size, 10);
void SeqListInsert(SL* ps, int pos, SLDataType x)
{
assert(pos >= 0 && pos <= ps->size);
int end = ps->size - 1;
SeqListCheckCapacity(ps);
while (end >= pos)
{
ps->a[end + 1] = ps->a[end];
end--;
}
ps->a[pos] = x;
ps->size++;
return;
}
7.删除功能
思路是先找到插入位置的后一个位置,然后一个一个数据往前一个位置去覆盖。
注意:删除函数可以实现头删功能和尾删功能
头删:SeqListErase(ps, 0);
尾删:SeqListErase(ps, ps->size - 1);
void SeqListErase(SL* ps, int pos)
{
assert(pos >= 0 && pos < ps->size);
int begin = pos + 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
begin++;
}
ps->size--;
return;
}
8.此程序共包含4个文件,2个.c文件和2个.h文件
8.1 SeqList.h文件
文件中包含了函数功能的头文件以及对应的结构体。
#pragma once
#include <stdio.h>
#include <stdlib.h>
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* a;
int size;
int capacity;
}SL;
void SeqListInit(SL *ps);
void SeqListPushBack(SL *ps, SLDataType x);
void SeqListPopBack(SL *ps);
void SeqListPushFront(SL *ps, SLDataType x);
void SeqListPopFront(SL *ps);
void SeqListCheckCapacity(SL* ps);
void SeqListFree(SL *ps);
int SeqListFind(SL* ps, SLDataType x);
void SeqListInsert(SL* ps, int pos, SLDataType x);
void SeqListErase(SL* ps, int pos);
void SeqListPrint(SL *ps);
8.2 SeqList.c文件
文件中包含了功能函数的具体实现方式。
#define _CRT_SECURE_NO_WARNINGS
#include "SeqList.h"
#include <assert.h>
void SeqListInit(SL *ps)
{
ps->a = NULL;
ps->size = ps->capacity = 0;
if ((NULL == ps->a) && (0 == ps->size) && (0 == ps->capacity))
{
printf("Init Success!\n");
}
else
{
printf("Init Fail!\n");
}
return;
}
void SeqListPushBack(SL *ps, SLDataType x)
{
SeqListCheckCapacity(ps);
ps->a[ps->size] = x;
ps->size++;
return;
}
void SeqListPopBack(SL* ps)
{
assert(ps->size > 0);
ps->size--;
return;
}
void SeqListPushFront(SL* ps, SLDataType 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++;
return;
}
void SeqListPopFront(SL* ps)
{
assert(ps->size > 0);
int begin = 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
begin++;
}
ps->size--;
return;
}
void SeqListCheckCapacity(SL* ps)
{
if (ps->capacity == ps->size)
{
int newCapacity = (ps->capacity == 0) ? 4 : ps->capacity * 2;
SLDataType* temp = (SLDataType*)realloc(ps->a, newCapacity * sizeof(SLDataType));
if (NULL == temp)
{
printf("realloc fail!\n");
exit(-1);
}
ps->a = temp;
ps->capacity = newCapacity;
}
return;
}
void SeqListFree(SL* ps)
{
free(ps->a);
ps->a = NULL;
ps->capacity = ps->size = 0;
return;
}
void SeqListPrint(SL* ps)
{
assert(ps != NULL);
int i = 0;
for (i = 0; i < (ps->size); i++)
{
printf("a[%d] = %d\n", i, ps->a[i]);
}
printf("\n");
return;
}
int SeqListFind(SL* ps, SLDataType x)
{
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (ps->a[i] == x)
{
printf("找到x,下标为%d\n", i);
return i;
}
}
printf("x 不在顺序表中!\n");
return -1;
}
void SeqListInsert(SL* ps, int pos, SLDataType x)
{
assert(pos >= 0 && pos <= ps->size);
int end = ps->size - 1;
SeqListCheckCapacity(ps);
while (end >= pos)
{
ps->a[end + 1] = ps->a[end];
end--;
}
ps->a[pos] = x;
ps->size++;
return;
}
void SeqListErase(SL* ps, int pos)
{
assert(pos >= 0 && pos < ps->size);
int begin = pos + 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
begin++;
}
ps->size--;
return;
}
8.3 test.h文件
文件中定义了控制宏的开关,用来测试时方便的控制插入和删除的个数。
#pragma once
#define SEQ_LIST_PUSH_BACK_NUM 5
#define SEQ_LIST_POP_BACK_NUM 3
#define SEQ_LIST_PUSH_FRONT_NUM 15
#define SEQ_LIST_POP_FRONT_NUM 3
8.4 test.c文件
用来进行相应功能的测试,TestSeqList1()和TestSeqList2(),分别测试尾插、尾删和头插、头删。使用者可以自己控制注释,来测试不同的功能。
#define _CRT_SECURE_NO_WARNINGS
#include "SeqList.h"
#include "test.h"
void TestSeqList1()
{
SL s;
int i = 0;
SeqListInit(&s);
for (i = 0; i < SEQ_LIST_PUSH_BACK_NUM; i++)
{
SeqListPushBack(&s, i);
}
SeqListPrint(&s);
for (i = 0; i < SEQ_LIST_POP_BACK_NUM; i++)
{
SeqListPopBack(&s);
}
SeqListPrint(&s);
SeqListFree(&s);
return;
}
void TestSeqList2()
{
SL s;
int i = 0;
SeqListInit(&s);
for (i = 0; i < SEQ_LIST_PUSH_BACK_NUM; i++)
{
SeqListPushBack(&s, i);
}
SeqListPrint(&s);
for (i = 10; i < SEQ_LIST_PUSH_FRONT_NUM; i++)
{
SeqListPushFront(&s, i);
}
SeqListPrint(&s);
for (i = 0; i < SEQ_LIST_POP_FRONT_NUM; i++)
{
SeqListPopFront(&s);
}
SeqListPrint(&s);
SeqListFree(&s);
return;
}
void TestSeqList3()
{
SL s;
int i = 0;
SeqListInit(&s);
for (i = 0; i < SEQ_LIST_PUSH_BACK_NUM; i++)
{
SeqListPushBack(&s, i);
}
SeqListPrint(&s);
SeqListFind(&s, 1);
SeqListInsert(&s, 3, 100);
SeqListPrint(&s);
SeqListErase(&s, 2);
SeqListPrint(&s);
SeqListFree(&s);
return;
}
int main()
{
TestSeqList1();
return 0;
}
9.测试结果
9.1 测试尾插和尾删的运行结果
从运行结果可以看出,尾插函数插入了5个元素分别是0,1,2,3,4。执行过尾删后,删除了后边的3个元素。
9.2 测试头插和头删的运行结果
从运行结果可以看出,通过尾插先插入5个元素分别是0,1,2,3,4。
然后执行头插,插入了10,11,12,13,14这5个元素,最后执行了头删,删除了前边的3个元素。
9.3 测试查找、插入和删除的运行结果
从运行结果可以看出,通过查找的函数,找到数字1在下标为1的位置上;
然后执行插入函数,可以看出在下标为3的位置上,插入数字100;
最后执行删除函数,可以看出删除了下标为2的位置上的数字2。
10.温馨提示
插入和删除的个数,均是通过test.h中的宏定义来控制的。