静态顺序表

静态顺序表要求数据的放入是连续的,而数组是可以往任一位置放入的,所以这里是有区别的。

在此我们用数组来实现静态顺序表的结构

#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;
		}
	}
}

总结:静态顺序表操作固然简单,可是数组的大小却是确定的,当存放数据过多而数组过小就会存在数据放不下的问题。可将数组定义过大,当只存放较小数据的时候又会出现空间大量浪费的现象。为了解决这个问题,就出现了下面的动态顺序表(下篇博客^-^)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值