概念及结构
顺序表是把数据元素存储在一段物理地址连续的存储单元上的线性结构,一般采用数组存储,增删改查等操作也在数组上完成。
顺序表一般可分为:
1.静态顺序表:使用定长数组存储
2.动态顺序表:使用动态开辟的数组存储
而静态顺序表有很大的缺陷,只适用于知道要存多少数据的情况,而且容易造成空间不足或者浪费,所以现实一般使用动态顺序表。以下是动态顺序表的实现:
代码实现
SList.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<malloc.h>
typedef int SLDataType;
typedef struct SList
{
SLDataType* _array;
size_t _size;
size_t _capacity;
}SList;
void SListInit(SList* psl, size_t capacity);//初始化
void SListDestroy(SList* psl);//销毁
void CheckCapacity(SList* psl);//增加容量(开空间)
void SListPushFront(SList* psl, SLDataType x);//头插
void SListPushBack(SList* psl, SLDataType x);//尾插
void SListPopFront(SList* psl);//头删
void SListPopBack(SList* psl);//尾删
size_t SListFind(SList* psl, SLDataType x);//查找
void SListInsert(SList* psl, size_t pos, SLDataType x);//在pos节点的前面插入x
void SListErase(SList* psl, size_t pos);//删除pos节点
void SListRemove(SList* psl, SLDataType x);//删除值为x的节点
void SListModify(SList* psl, size_t pos, SLDataType x);//修改pos节点的值为x
void SListPrint(SList* psl);//打印顺序表
void SListBubbleSort(SList* psl);//冒泡排序
void SListBinaryFind(SList* psl, SLDataType x);//二分查找
void SListRemoveAll(SList* psl, SLDataType x);//删除所有值为x的节点
SList.c
#include"SList.h"
void Swap(SLDataType* p1, SLDataType* p2)
{
assert(p1 && p2);
SLDataType temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
void SListInit(SList* psl, size_t capacity)
{
assert(psl);
psl->_array = (SLDataType*)malloc(sizeof(SLDataType)*capacity);
if (psl->_array == NULL)
{
printf("malloc error");
exit(-1);
}
psl->_capacity = capacity;
psl->_size = 0;
}
void SListDestroy(SList* psl)
{
assert(psl);
free(psl->_array);
psl->_array = NULL;
}
void CheckCapacity(SList* psl)
{
assert(psl);
size_t newcapacity = (psl->_capacity) * 2;
if (psl->_size < psl->_capacity)
{
return;
}
else if (psl->_capacity == psl->_size)
{
SLDataType* newarray = (SLDataType*)realloc(psl->_array, sizeof(SLDataType)*newcapacity);
if (newarray == NULL)
{
printf("realloc error");
}
psl->_array = newarray;
psl->_capacity = newcapacity;
}
}
void SListPushFront(SList* psl, SLDataType x)
{
assert(psl);
CheckCapacity(psl);
psl->_size += 1;
for (size_t i = psl->_size - 1; i > 0; --i)
{
psl->_array[i] = psl->_array[i - 1];
}
psl->_array[0] = x;
}
void SListPushBack(SList* psl, SLDataType x)
{
assert(psl);
CheckCapacity(psl);
psl->_size += 1;
psl->_array[psl->_size - 1] = x;
}
void SListPopFront(SList* psl)
{
assert(psl && psl->_size > 0);
for (size_t i = 0; i <= psl->_size - 1; i++)
{
psl->_array[i] = psl->_array[i + 1];
}
psl->_size--;
}
void SListPopBack(SList* psl)
{
assert(psl && psl->_size > 0);
psl->_size--;
}
size_t SListFind(SList* psl, SLDataType x)
{
assert(psl);
size_t input = psl->_size;
while (input)
{
if (psl->_array[input - 1] == x)
{
return input - 1;
}
input--;
}
}
void SListInsert(SList* psl, size_t pos, SLDataType x)
{
assert(psl->_size > 0);
CheckCapacity(psl);
psl->_size += 1;
for (size_t i = psl->_size - 1; i >= pos; --i)
{
psl->_array[i] = psl->_array[i - 1];
}
psl->_array[pos] = x;
}
void SListErase(SList* psl, size_t pos)
{
assert(psl->_size > 0);
for (size_t i = pos; i < psl->_size - 1; i++)
{
psl->_array[i] = psl->_array[i + 1];
}
psl->_size--;
}
void SListRemove(SList* psl, SLDataType x)
{
assert(psl->_size > 0);
for (size_t i = 0; i < psl->_size; i++)
{
if (psl->_array[i] == x)
{
SListErase(psl, i);
return;
}
}
}
void SListModify(SList* psl, size_t pos, SLDataType x)
{
assert(psl->_size > 0);
psl->_array[pos] = x;
}
void SListPrint(SList* psl)
{
assert(psl);
for (size_t i = 0; i < psl->_size; i++)
{
printf("%d->", psl->_array[i]);
}
printf("\n");
}
void SListBubbleSort(SList* psl)
{
assert(psl);
for (size_t i = 0; i <= psl->_size - 1; i++)
{
size_t flag = 0;
for (size_t j = 0; j < psl->_size - 1 - i; j++)
{
if (psl->_array[j] > psl->_array[j + 1])
{
Swap(&(psl->_array[j]), &(psl->_array[j + 1]));
flag++;
}
}
if (flag == 0)
{
break;
}
}
}
void SListBinaryFind(SList* psl, SLDataType x)
{
assert(psl);
SListBubbleSort(psl);
size_t left = 0;
size_t right = psl->_size - 1;
size_t flag = 0;
while (left <= right)
{
size_t middle = left + (right - left) / 2;
if (psl->_array[middle] == x)
{
flag = 1;
printf("找到了,下标为%d\n", middle);
break;
}
else if(x < psl->_array[middle])
{
right = middle + 1;
}
else
{
left = middle + 1;
}
}
if (flag == 0)
{
printf("找不到\n");
}
}
void SListRemoveAll(SList* psl, SLDataType x)
{
assert(psl);
for (size_t i = 0; i < psl->_size; i++)
{
if (psl->_array[i] == x)
{
SListErase(psl, i);
}
}
}
总结
相对于静态顺序表而言,动态顺序表虽然有了不小的优化,但是还是存在一些问题:
1.中间/头部的插入和删除操作,时间复杂度较高,为O(N)
2.增容需要申请新的空间,拷贝数据,然后释放旧的空间,会有不小的消耗
3.增容 一般呈2倍的增长,势必会有一定的空间被浪费