静态顺序表要求数据的放入是连续的,而数组是可以往任一位置放入的,所以这里是有区别的。
在此我们用数组来实现静态顺序表的结构
#define MAX 50
#define DataType int
typedef struct SeqList
{
//用来存放数据的空间
DataType arr[MAX];
//用来计算顺序表中有效元素的个数
int size;
}SeqList;
静态顺序表中,我们实现了以下的基本操作
//静态顺序表的初始化
void SeqListInit(SeqList *ps);
//静态顺序表的销毁
void SeqListDestory(SeqList *ps);
//静态顺序表的打印
void SeqListPrint(SeqList *ps);
//静态顺序表的插入:尾插、头插、插入指定位置
void SeqListPushBack(SeqList *ps, DataType data);
void SeqListPushFront(SeqList *ps, DataType data);
void SeqListInsert(SeqList *ps, int pos, DataType data);
//静态顺序表的删除:尾删、头删、删除指定位置、删除指定数据、删除线性表中所有指定数据
void SeqListPopBack(SeqList *ps);
void SeqListPopFront(SeqList *ps);
void SeqListErase(SeqList *ps, int pos);
void SeqListRemove(SeqList *ps, DataType data);
void SeqListRemoveAll(SeqList *ps, DataType data);
//静态顺序表的数据更新
void SeqListUpdata(SeqList *ps, int pos, DataType data);
//静态顺序表的查询
int SeqListFind(SeqList *ps, DataType data);
//静态顺序表的排序:选择排序、冒泡排序
void SeqListSelectSort(SeqList *ps);
void SeqListbubbleSort(SeqList *ps);
1)初始化
void SeqListInit(SeqList *ps)
{
//多多使用assert断言,以防程序出现不可测得问题
assert(ps != NULL);
//将顺序表中的数组进行赋值
memset(ps->arr, 0x00, MAX * sizeof(DataType));
/顺序表中的有效元素初始为0
ps->size = 0;
}
2)销毁
void SeqListDestory(SeqList *ps)
{
assert(ps != NULL);
//销毁的时候仅需将有效元素个数设置为0即可
ps->size = 0;
}
3)打印
void SeqListPrint(SeqList *ps)
{
assert(ps != NULL);
//使用for循环依次打印所有的有效元素的个数
for (int i = 0; i < ps->size; i++)
{
printf("%d->", ps->arr[i]);
}
printf("NULL\n");
}
4)插入
void SeqListPushBack(SeqList *ps, DataType data)
{
assert(ps != NULL);
//想要插入,首先要求有效元素个数不能超过数组最大所能放入的元素个数
assert(ps->size < MAX);
//size代表有效元素的个数,实则指的是可放入元素的数组下标
ps->arr[ps->size] = data;
//放入元素之后一定要记得将有效元素的个数加1
ps->size++;
}
void SeqListPushFront(SeqList *ps, DataType data)
{
assert(ps != NULL);
assert(ps->size < MAX);
//记录有效元素的个数
int i = ps->size;
//因为要头插,所以首先需要将数组中的元素均向后搬移一个单位
for (; i > 0; i--)
{
//切记应从后向前搬移(可以思考一下原因-->否则数据会被覆盖)
ps->arr[i] = ps->arr[i - 1];
}
//将数组的第一个位置留出来进行数据的头插
ps->arr[i] = data;
ps->size++;
}
void SeqListInsert(SeqList *ps, int pos, DataType data)
{
assert(ps != NULL);
assert(ps->size < MAX);
int i = ps->size;
//只需将pos以后的元素均向后搬移一个单位,流出pos的插入位置即可
for (; i > pos; i--)
{
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[i] = data;
ps->size++;
}
5)删除
void SeqListPopBack(SeqList *ps)
{
assert(ps != NULL);
//想要删除必须保证数组中至少有一个有效元素
assert(ps->size > 0);
//删除后一定要记得将数组中的有效元素个数减1
ps->size--;
}
void SeqListPopFront(SeqList *ps)
{
assert(ps != NULL);
assert(ps->size > 0);
//将数组中的有效元素均向前搬移一个单位
for (int i = 1; i < ps->size; i++)
{
//切记应从前向后搬移(想想为什么-->以防数据被覆盖)
ps->arr[i - 1] = ps->arr[i];
}
ps->size--;
}
void SeqListErase(SeqList *ps, int pos)
{
assert(ps != NULL);
assert(ps->size > 0);
int space;
//同理将pos后的有效元素均向前搬移一个单位
for (space = pos; space < ps->size - 1; space++)
{
ps->arr[space] = ps->arr[space + 1];
}
ps->size--;
}
void SeqListRemove(SeqList *ps, DataType data)
{
assert(ps != NULL);
assert(ps->size > 0);
//这里调用的查找函数返回的是找到数据的下标
int pos = SeqListFind(ps, data);
if (pos != -1)
{
for (int i = pos + 1; i < ps->size; i++)
{
ps->arr[i - 1] = ps->arr[i];
}
}
ps->size--;
}
void SeqListRemoveAll(SeqList *ps, DataType data)
{
assert(ps != NULL);
assert(ps->size > 0);
#if 0
/*用一个循环,一个一个找,一个一个删*/
int pos;
while ((pos = SeqListFind(ps, data)) != -1)
{
SeqListErase(ps, pos);
}
#endif
/*将指定数据进行覆盖*/
int i = 0;
int j = 0;
while (i < ps->size)
{
if (ps->arr[i] == data)
{
//指指定数据的下一个位置的下标
i++;
}
else
{
//将指定数据进行覆盖(若i,j代表同一下标则此步骤暂且没用)
ps->arr[j] = ps->arr[i];
//覆盖后两个下标 统一后移一位
i++;
j++;
}
}
//最终j就代表目前数组中有效元素的个数
ps->size = j;
}
6)数据更新
void SeqListUpdata(SeqList *ps, int pos, DataType data)
{
assert(ps != NULL);
assert(ps->size > pos);
//将指定位置改为指定数据
ps->arr[pos] = data;
}
7)查找(找到返回对应下标,没找到返回-1)
int SeqListFind(SeqList *ps, DataType data)
{
assert(ps != NULL);
for (int i = 0; i < ps->size; i++)
{
if (ps->arr[i] == data)
{
return i;
}
}
return -1;
}
8)排序
//定义一个简单的交换函数,实现两个数据的交换
void swap(DataType *p, DataType *q)
{
DataType temp;
temp = *p;
*p = *q;
*q = temp;
}
void SeqListSelectSort(SeqList *ps)
{
assert(ps != NULL);
assert(ps->size > 0);
/*
minSpace --> 最小的数
maxSpace --> 最大的数
minIndex --> 最小数的位置
maxIndex --> 最大数的位置
*/
int i;
int minIndex, maxIndex;
int minSpace = 0;
int maxSpace = ps->size - 1;
while (minSpace < maxSpace)
{
//最大值最小值均从开始的位置找
minIndex = minSpace;
maxIndex = minSpace;
//以下循环结束可以得到当前未排序列中最大值和最小值得下标
for (i = minSpace; i <= maxSpace; i++)
{
if (ps->arr[i] < ps->arr[minIndex])
{
minIndex = i;
}
if (ps->arr[i] > ps->arr[maxIndex])
{
maxIndex = i;
}
}
//将最小值(minIndex)放入最小下标的位置(minSpace)
swap(&(ps->arr[minIndex]), &(ps->arr[minSpace]));
//以下的判断极为重要
//若交换前最小位置(minSpace)存放的正好是找到的最大的数
//那交换后最大的数就被转移到minIndex中了
//为了后面能将最大值(maxIndex)正确的放入最大下标的位置(maxSpace)中
//此时需要将转移后的最大值的位置再告诉(maxIndex)
if (ps->arr[maxIndex] == ps->arr[minSpace])
{
maxIndex = minIndex;
}
//将最大值(maxIndex)放入最大下标的位置(maxSpace)
swap(&(ps->arr[maxIndex]), &(ps->arr[maxSpace]));
//一次循环过后,已经将当前的最大最小值放在正确的位置了,现在应向中间缩小再次循环了
minSpace++;
maxSpace--;
}
}
void SeqListbubbleSort(SeqList *ps)
{
assert(ps != NULL);
assert(ps->size > 0);
int i, j, flag;
for (i = 0; i < ps->size - 1; i++)
{
flag = 1;
//该for循环每次可将一个最大的数据找到并放置最后
for (j = 1; j < ps->size - i; j++)
{
if (ps->arr[j - 1] > ps->arr[j])
{
swap(&(ps->arr[j - 1]), &(ps->arr[j]));
flag = 0;
}
}
//flag仅是一个检验值,当上面的循环没有改变flag的值时说明当前已经排好序了,不需要再次循环
if (flag)
{
break;
}
}
}
总结:静态顺序表操作固然简单,可是数组的大小却是确定的,当存放数据过多而数组过小就会存在数据放不下的问题。可将数组定义过大,当只存放较小数据的时候又会出现空间大量浪费的现象。为了解决这个问题,就出现了下面的动态顺序表(下篇博客^-^)