顺序表的概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组 上完成数据的增删查改。
顺序表一般可以分为:
- 静态顺序表:使用定长数组存储。
- 动态顺序表:使用动态开辟的数组存储
// 顺序表的静态存储
#define N 100
typedef int DataType;
typedef struct SeqList {
DataType array[N]; // 定长数组 比特科技
size_t size; // 有效数据的个数
}SeqList;
静态顺序表只适用于知道了需要存多少数据的场景,比较死板,其中的定长数组更是存在严重问题,空间开多了浪费,开少了不够用。
在日常工作中,基本都是使用动态顺序表,根据需要动态的分配空间大小。
所以下面实现动态顺序表:
头文件:“SeqList.h”
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
typedef size_t SLDataType;
#define DEFAULT_SIZE 5
#define INC_SIZE 2
typedef struct SeqList {
SLDataType* array;
size_t size; //有效数据个数
size_t capacity; //数据容量
}SeqList;
void SeqListInit(SeqList* pList);//初始化
void SeqListDestory(SeqList* pList);//销毁
void CheckCapacity(SeqList* pList);//检查容量是否需要增容
void SeqListPushBack(SeqList* pList, SLDataType data);//尾插
void SeqListPopBack(SeqList* pList);//尾删
void SeqListPushFront(SeqList* pList, SLDataType data);//头插
void SeqListPopFront(SeqList* pList);//头删
size_t SeqListFind(SeqList* pList, SLDataType data);//在顺序表中查找指定元素
void SeqListInsert(SeqList* pList, size_t pos, SLDataType data);//在指定位置插入指定元素
void SeqListErase(SeqList* pList, size_t pos);//删除指定位置的元素
void SeqListRemove(SeqList* pList, SLDataType data);//删除指定元素
void SeqListRemoveAll(SeqList* pList, SLDataType data); //删除顺序表中所有指定元素
void SeqListModify(SeqList* pList, size_t pos, SLDataType data);//修改指定位置的元素为指定值
void SeqListPrint(SeqList* pList);//打印顺序表
void Reverse(SeqList* pList);//逆置顺序表
void SeqListBubbleSort(SeqList* pList);//冒泡排序顺序表
size_t SeqListBinaryFind(SeqList* pList, SLDataType data);//在顺序表中二分查找指定元素
功能实现:“SeqList.c”
#include"SeqList.h"
//初始化顺序表
void SeqListInit(SeqList* pList)
{
assert(pList);
pList->size = 0;
pList->array = (SLDataType *)malloc(sizeof(SLDataType)*DEFAULT_SIZE);
if (!pList->array)
{
perror("malloc");
return;
}
memset(pList->array, 0, sizeof(SLDataType)*DEFAULT_SIZE);
}
//销毁顺序表
void SeqListDestory(SeqList* pList)
{
free(pList->array);
pList = NULL;
}
//检查顺序表的容量
void CheckCapacity(SeqList* pList)
{
assert(pList);
if (pList->size == pList->capacity)
{
SLDataType *ret = (SLDataType *)realloc(
pList->array, sizeof(SLDataType)*DEFAULT_SIZE + INC_SIZE);
if (!ret)
{
perror("malloc");
}
pList->array = ret;
pList->capacity += INC_SIZE;
}
}
//打印顺序表
void SeqListPrint(SeqList* pList)
{
assert(pList);
for (size_t i = 0; i < pList->size; i++)
{
printf("%d ", pList->array[i]);
}
}
//尾插
void SeqListPushBack(SeqList* pList, SLDataType data)
{
assert(pList);
if (pList->size == pList->capacity)
{
CheckCapacity(pList);
}
pList->array[pList->size] = data;
pList->size++;
}
//尾删
void SeqListPopBack(SeqList* pList)
{
assert(pList);
if (pList->size == 0)
{
printf("顺序表内无数据\n");
return;
}
pList->size--;
}
//头插
void SeqListPushFront(SeqList* pList, SLDataType data)
{
assert(pList);
if (pList->size == pList->capacity)
{
CheckCapacity(pList);
}
//注意这里的循环条件是从后向前的,把前一个值赋给后一个值,只能是i-1赋给i
//而不可以是i赋给i+1,两者本质上是一样的,但后者在赋值的过程中,
//会出现越界的情况,程序会崩溃
for (int i = pList->size; i > 0; i--)
{
pList->array[i] = pList->array[i - 1];
}
pList->array[0] = data;
pList->size++;
}
//头删
void SeqListPopFront(SeqList* pList)
{
assert(pList);
if (pList->size == 0)
{
printf("顺序表内无数据\n");
return;
}
//从头遍历,将数组中后一个数赋给前一个,达到覆盖的效果
for (size_t i = 0; i < pList->size; i++)
{
pList->array[i] = pList->array[i + 1];
}
pList->size--;
}
//查找
size_t SeqListFind(SeqList* pList, SLDataType data)
{
assert(pList);
for (size_t i = 0; i < pList->size; ++i)
{
if (pList->array[i] == data)
return i + 1;
}
//没找到
return -1;
}
//在指定位置插入元素
void SeqListInsert(SeqList* pList, size_t pos, SLDataType data)
{
assert(pList);
if (pList->size == pList->capacity)
{
CheckCapacity(pList);
}
for (size_t i = pList->size; i > pos - 1; --i)
{
pList->array[i] = pList->array[i - 1];
}
pList->array[pos - 1] = data;
pList->size++;
}
//删除指定位置的元素
void SeqListErase(SeqList* pList, size_t pos)
{
assert(pList);
if (pos>0 && pos<pList->size)
{
for (size_t i = pos - 1; i < pList->size; ++i)
{
pList->array[i] = pList->array[i + 1];
}
pList->size--;
}
}
//删除指定元素
void SeqListRemove(SeqList* pList, SLDataType data)
{
assert(pList);
size_t pos = SeqListFind(pList, data);
if (pos)
{
SeqListErase(pList, pos);
}
}
//删除数组中所有指定元素
void SeqListRemoveAll(SeqList* pList, SLDataType data)
{
assert(pList);
for (size_t i = 0; i < pList->size; i++)
{
size_t i = SeqListFind(pList, data);
if (i < 0)
{
printf("没有找到");
return;
}
SeqListErase(pList, i);
}
}
//修改指定位置的元素为给定元素
void SeqListModify(SeqList* pList, size_t pos, SLDataType data)
{
assert(pList);
if (pos>0 && pos < pList->size)
{
for (size_t i = pos - 1; i < pList->size; ++i)
{
pList->array[pos] = data;
return;
}
}
else
{
printf("wrong pos");
}
}
void Swap(size_t *a, size_t *b)
{
size_t tmp = *a;
*a = *b;
*b = tmp;
}
//逆置顺序表
void Reverse(SeqList* pList)
{
assert(pList);
size_t left = 0;
size_t right = pList->size - 1;
while(left<right)
{
Swap(pList->array + left, pList->array + right);
left++;
right--;
}
}
//冒泡排序顺序表
void SeqListBubbleSort(SeqList* pList)
{
assert(pList);
for (size_t i = 1; i < pList->size - 1; ++i)
{
size_t flag = 0;
for (size_t j = 0; j < pList->size - i; ++j)
{
if (pList->array[j] > pList->array[j + 1])
{
Swap(pList->array + j, pList->array + j + 1);
flag++;
}
}
if (flag == 1)
{
return;
}
}
}
//二分查找指定元素
size_t SeqListBinaryFind(SeqList* pList, SLDataType data)
{
assert(pList);
size_t left = 0;
size_t right = pList->size - 1;
SeqListBubbleSort(pList);
while (left < right)
{
size_t mid = left + (right - left) / 2;
if (pList->array[mid] < data)
left = mid + 1;
else if (pList->array[mid] > data)
right = mid - 1;
else
return mid + 1;
}
return -1;
}
测试:“Test.c”
#include"SeqList.h"
void test()
{
SeqList pList;
SeqListInit(&pList);//初始化
SeqListPushBack(&pList, 1);
SeqListPushBack(&pList, 2);
SeqListPushBack(&pList, 2);
SeqListPushBack(&pList, 2);
SeqListPushBack(&pList, 2);
SeqListPushBack(&pList, 5);
SeqListPushBack(&pList, 2);
SeqListPushBack(&pList, 3);
SeqListPushBack(&pList, 4);
SeqListPushBack(&pList, 5);
SeqListPushBack(&pList, 6);
SeqListPrint(&pList);
printf("\n");
SeqListPopBack(&pList);
SeqListPopBack(&pList);
SeqListPrint(&pList);
printf("\n");
SeqListInsert(&pList, 2, 9);
SeqListPrint(&pList);
printf("\n");
SeqListRemoveAll(&pList, 2);
SeqListPrint(&pList);
printf("\n");
/*SeqListErase(&pList, 3);
SeqListPrint(&pList);
printf("\n");
printf("%d", SeqListFind(&pList, 4));
printf("\n");
SeqListRemove(&pList, 1);
SeqListPrint(&pList);
printf("\n");
SeqListModify(&pList, 2, 6);
SeqListPrint(&pList);
printf("\n");
SeqListBubbleSort(&pList);
SeqListPrint(&pList);
printf("\n");
printf("%d", SeqListBinaryFind(&pList, 6));
printf("\n");
Reverse(&pList);
SeqListPrint(&pList);
printf("\n");*/
/*SeqListPushFront(&pList, 4);
SeqListPushFront(&pList, 5);
SeqListPushFront(&pList, 6);
SeqListPrint(&pList);
printf("\n");
SeqListPopFront(&pList);
SeqListPopFront(&pList);
SeqListPrint(&pList);
printf("\n");*/
SeqListDestory(&pList);
}
int main()
{
test();
return 0;
}
本文详细介绍顺序表的概念、结构及其实现方法,包括静态和动态顺序表的区别,重点讲解了动态顺序表的增删查改操作,如尾插、尾删、头插、头删等,并介绍了查找、插入、删除、修改、排序和逆置等功能。
453

被折叠的 条评论
为什么被折叠?



