线性表和链表是数据结构中很重要的存储数据的结构,也是数据结构最基础的内容
一.顺序表(静态)
顺序表是用一段地址连续的存储单元依次存放数据元素的线性结构。地址连续的空间我们一般采用数组来表示,顺序表又分为静态顺序表和动态顺序表,静态顺序表只可存储固定数量的数据,而动态顺序表则可以通过在使用过程中的不断扩容来改变其容量的大小。
1.创建顺序表
创建一个顺序表需要一个存放数据的数组和一个标志其容量的数据,所以我们用一个结构体来将这两个元素构成一个顺序表的结构类型。
typedef int Datatype; //为了适用于多种数据类型
#define MAX_SIZE 100
typedef struct Seqlist
{
Datatype data[MAX_SIZE];
int size; //当前有效容量
}Seqlist;
2.初始化顺序表
初始化只需要将其有效容量size置为0即可。
void SeqlistInit(Seqlist *pSeqlist)
{
assert(pSeqlist);
pSeqlist->size = 0;
}
3.顺序表的头插
顺序表的头插比较麻烦,首先应该先判断该顺序表中有无元素,若有将新元素插入即可,可若有元素就必须先将表中的第一个位置空出来以便插入,就需要将所有元素向后挪动一格,这时候就有一个新的问题,如果表中元素已满无法向后挪动则这次头插失败。挪动的时候你要考虑挪动的顺序,一定是从当前表中最后一个有效元素开始挪动,否则会造成元素的丢失。
void SeqlistPushfront(Seqlist*pSeqlist, Datatype d)
{
assert(pSeqlist); //在对指针解引用之前必须判断它不为空,否则会越界访问
if (pSeqlist->size == MAX_SIZE) //判断顺序表是否已满
{
return;
}
int i = 0;
for (i = pSeqlist->size; i > 0; i--)
{
pSeqlist->data[i] = pSeqlist->data[i - 1];
}
pSeqlist->data[0] = d;
pSeqlist->size++; //成功头插后,size+1
}
4.顺序表尾插
尾插相对于头插来说就简便了很多,不用牵扯原本表内有效元素的移动,只需要判断顺序表是否已满,未满则在下标为size的地方插入(因为以数组存储,当有size个元素时其下标为0~size-1)即可。
void SeqlistPushback(Seqlist*pSeqlist, Datatype d)
{
assert(pSeqlist); //此处断言不可省略
if (pSeqlist->size == MAX_SIZE)
{
return;
}
pSeqlist->data[pSeqlist->size] = d;
pSeqlist->size++;
}
5.顺序表头删
顺序表的头删和头插一样是在如果表中有元素的情况下需要移动当前表中的元素,与头插不同的是移动的方向相反。在删除前需要判断表中是否有元素,若表中没有元素则无法完成删除
void SeqlistPopfront(Seqlist*pSeqlist)
{
assert(pSeqlist);
assert(pSeqlist->size > 0);
int i = 0;
for (; i <= pSeqlist->size - 2;i++)
{
pSeqlist->data[i] = pSeqlist->data[i + 1];
}
pSeqlist->size--;
}
6.顺序表尾删
void SeqlistPopback(Seqlist*pSeqlist)
{
assert(pSeqlist);
assert(pSeqlist->size > 0);
pSeqlist->size--;
}
7.在指定位置前插入
void SeqlistInsert(Seqlist*pSeqlist, int pos, Datatype d)
{
assert(pSeqlist);
if (pSeqlist->size == MAX_SIZE)
{
return;
}
int i = 0;
for (i = pSeqlist->size; i > pos; i--)
{
pSeqlist->data[i] = pSeqlist->data[i - 1];
}
pSeqlist->data[pos] = d;
pSeqlist->size++;
}
8.查找指定元素,若有则返回下标,否则返回-1
查找元素就是从顺序表的第一个元素开始遍历该顺序表,依次比较其值与指定元素是否相等,相等则返回下标,否则指针+1判断下一个元素。若遍历完表中所有元素仍无与之匹配的则返回-1.
bool Find(const Seqlist *pSeqlist, Datatype d)
{
int i = 0;
for (i = 0; i < pSeqlist->size; i++)
{
if (pSeqlist->data[i] == d)
{
return i;
}
}
return -1;
}
9.删除指定位置的元素
所有的删除都要判断顺序表是否非空
void SeqlistErase(Seqlist*pSeqlist, int pos)
{
int i = 0;
assert(pSeqlist);
assert(pSeqlist->size > 0);
assert(pos >= 0 && pos < pSeqlist->size);
for (i = pos; i < pSeqlist->size -1; i++)
{
pSeqlist->data[i] = pSeqlist->data[i + 1];
}
pSeqlist->size--;
}
10.删除指定元素(若表中有多个只可删除第一个)
删除指定元素可以调用Find函数和Erase函数,先用Find函数查找该元素,若有则接受其在顺序表的下标,调用Erase删除即可。
void SeqlistRemove(Seqlist*pSeqlist, Datatype d)
{
int i = 0;
assert(pSeqlist && pSeqlist->size>0);
int pos = Find(pSeqlist, d);
if (pos == -1)
{
return;
}
SeqlistErase(pSeqlist, pos);
}
11.删除指定所有元素
通过新建数组,把不等于 data 的数据 copy 到 extra
void RemoveAll(Seqlist *pSeqlist, Datatype d)
{
int i = 0;
int j = 0;
assert(pSeqlist && pSeqlist->size > 0);
for (; i < pSeqlist->size; i++)
{
if (pSeqlist->data[i] != d)
{
pSeqlist->data[j++] = pSeqlist->data[i];
}
}
pSeqlist->size = j;
}
12.顺序表的判空,判满以及查看当前有效元素个数
<1>判空
不为空则返回当前有效size大小。
bool SeqlistEmpty(const Seqlist*pSeqlist)
{
return pSeqlist->size;
}
<2>判满
返回与MAX_SIZE是否相等
bool Full(const Seqlist*pSeqlist)
{
return pSeqlist->size==MAX_SIZE;
}
<3>当前有效元素个数
int SeqlistSize(const Seqlist*pSeqlist)
{
return pSeqlist->size;
}
13.对顺序表中的元素进行冒泡排序
为了方便后面的冒泡排序首先写了swap函数用以交换两个数的值,代码如下
void swap(Datatype *s1,Datatype *s2) //一般进行交换是尽量传地址交换
{
Datatype tmp;
tmp = *s1;
*s1 = *s2;
*s2 = tmp;
}
以下是冒泡排序的程序,同普通的冒泡排序一样,两层循环遍历依次排序。
void BubbleSort(Seqlist *pSeqlist)
{
int i = 0;
int j = 0;
int flag = 0; //为了尽量的减少时间复杂度,尽量少做无用功
for (i = 0; i < pSeqlist->size - 1; i++)
{
for (j = 0; j < pSeqlist->size - i - 1; j++)
{
if (pSeqlist->data[j]>pSeqlist->data[j + 1])
{
swap(pSeqlist->data+j, pSeqlist->data+j + 1);
flag = 1;
}
}
if (flag = 0)
{
break;
}
}
}
14.打印顺序表
依次遍历并打印其data值即可。
void SeqlistShow(Seqlist*pSeqlist)
{
int i = 0;
for (i = 0; i < pSeqlist->size; i++)
{
printf("%d ", pSeqlist->data[i]);
}
printf("\n");
}
15.销毁顺序表
销毁和初始化一样只需要将其size置0即可。
void SeqlistDestroy(Seqlist *pSeqlist)
{
assert(pSeqlist);
pSeqlist->size = 0;
}