目录
- 前言
- 1.顺序表
- 1.1 顺序表介绍
- 1.2 顺序表基本操作代码实现
- 总结
前言
顺序表一般不会用来单独存储数据,但自身的优势,很多时候不得不使用顺序表。
1.顺序表
1.1 顺序表介绍
顺序表是物理结构连续的线性表,支持随机存取(底层是数组),存储密度大(只需存储数据元素,与链表相比,无需存储额外的指针)。缺点是,由于物理结构的连续,插入、删除要移动大量元素,时间复杂度为O(n),效率低下。
顺序表的组成如下,顺序表分为静态顺序表与动态顺序表。静态顺序表申请内存后不能更改,存在的问题是由于不确定需要的内存大小,如果开辟的内存块比较小,不够用;开辟过大,造成浪费。
动态顺序表可以在内存不够的时候调整顺序表的大小,注意,每次增加开辟的内存空间可以是原来内存的1~2倍,如果每次增加一个元素都要调整空间大小,效率太低。
1.2 顺序表基本操作代码实现
SeqList.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//静态顺序表
//typedef int SLDataType;
//#define N 100000
//
//struct SeqList
//{
// SLDataType a[N];
// int size;
//};
//动态顺序表
typedef int SLDataType;
#define INIT_CAPACITY 4
typedef struct SeqList
{
SLDataType* a;
int size;
int capacity;
}SL;
//增删查改
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);
void SLPrint(SL* ps);
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
void SLCheckCapacity(SL* ps);
int SLFind(SL* ps,SLDataType x);
SeqList.c
#include "SeqList.h"
void SLInit(SL* ps)
{
assert(ps);
ps->a = (SLDataType*)malloc(sizeof(SLDataType) * INIT_CAPACITY);
if (ps->a == NULL)
{
perror("malloc failed");
return;
}
ps->size = 0;
ps->capacity = INIT_CAPACITY;
}
void SLDestroy(SL* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->size = 0;
}
void SLPrint(SL* ps)
{
assert(ps);
for (int i = 0; i < ps->size; i++)
printf("%d ", ps->a[i]);
printf("\n");
}
void SLPushBack(SL* ps, SLDataType x)
{
/*SLCheckCapacity(ps);
ps->a[ps->size++] = x;*/
SLInsert(ps, ps->size, x);
}
void SLPopBack(SL* ps)
{
//assert(ps);
//assert(ps->size > 0);
//if (ps->size == 0)
//return;
ps->a[--ps->size] = 0;
//ps->size--;
SLErase(ps, ps->size - 1);
}
void SLCheckCapacity(SL* ps)
{
assert(ps);
if (ps->size == ps->capacity)
{
SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDataType));
if (tmp == NULL)
{
perror("realloc failed");
return;
}
ps->a = tmp;
ps->capacity *= 2;
}
}
void SLPushFront(SL* ps, SLDataType x)
{
/*SLCheckCapacity(ps);
int end = ps->size - 1;
while (end >= 0)
{
ps->a[end + 1] = ps->a[end];
end--;
}
ps->a[0] = x;
ps->size++;*/
SLInsert(ps, 0, x);
}
void SLPopFront(SL* ps)
{
/*assert(ps);
assert(ps->size > 0);
int begin = 1;
while (begin < ps->size)
ps->a[begin - 1] = ps->a[begin++];
ps->size--;*/
SLErase(ps, 0);
}
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(pos >= 0 && pos <= ps->size);
SLCheckCapacity(ps);
int end = ps->size - 1;
while (end >= pos)
ps->a[end + 1] = ps->a[end--];
ps->a[pos] = x;
ps->size++;
}
void SLErase(SL* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
int begin = pos + 1;
while (begin<ps->size)
ps->a[begin-1] = ps->a[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;
}
Test.c
#include "SeqList.h"
void TestSeqList1()
{
SL s;
SLInit(&s);
SLPushBack(&s, 1);
SLPushBack(&s, 2);
SLPushBack(&s, 3);
SLPushBack(&s, 4);
SLPushBack(&s, 5);
SLPushBack(&s, 6);
SLPushBack(&s, 7);
SLPushBack(&s, 8);
SLPushBack(&s, 9);
SLPrint(&s);
SLPopBack(&s);
SLPopBack(&s);
SLPrint(&s);
SLPopBack(&s);
SLPopBack(&s);
SLPopBack(&s);
SLPopBack(&s);
SLPopBack(&s);
SLPopBack(&s);
SLPopBack(&s);
SLPrint(&s);
SLPopBack(&s);
SLPushBack(&s, 10);
SLPushBack(&s, 20);
SLPrint(&s);
SLDestroy(&s);
}
void TestSeqList2()
{
SL s;
SLInit(&s);
for (int i = 0; i < 10; i++)
SLPushFront(&s, i);
SLPrint(&s);
SLPopFront(&s);
SLPopFront(&s);
SLPrint(&s);
SLInsert(&s, 2, 40);
SLPrint(&s);
SLInsert(&s, 8, 30);
SLPrint(&s);
SLErase(&s, 4);
SLPrint(&s);
printf("%d\n", SLFind(&s, 40));
}
int main()
{
TestSeqList2();
/*void* ptr1 = malloc(5);
printf("%p\n", ptr1);
void* ptr2 = malloc(6);
printf("%p\n", ptr2);*/
return 0;
}
//顺序表可以结合菜单进行操作,但要保证函数代码实现没有问题,否则在菜单中难以调试
//void menu()
//{
// printf("****************************************\n");
// printf("****** 1.尾插数据 2.尾删数据 ******\n");
// printf("****** 7.打印数据 0.退出程序 ******\n");
// printf("****************************************\n");
//}
//int main()
//{
// SL s;
// SLInit(&s);
// int option = -1;
// while (option != 0)
// {
// menu();
// scanf("%d", &option);
// switch (option)
// {
// case 1:
// printf("请依次输入要尾插的数据,以-1结束>:");
// int x = 0;
// while (x != -1)
// {
// scanf("%d", &x);
// SLPushBack(&s, x);
// }
// break;
// case 7:
// SLPrint(&s);
// break;
// default:
// break;
// }
// }
// return 0;
//}
总结
顺序表以及后续链表的学习都是对代码能力的锻炼,学习数据结构都是这个思路,逻辑结构、物理结构即基本操作实现。