初识线性表之------------动态顺序表

       之前在静态顺序表中已经对顺序表的相关知识进行过介绍,在这里就只对不同的地方进行介绍。
       首先,先定义顺序表的结构体:


#define DEFAULT_CAPACITY 3 
#define DEFAULT_ADD 2 

typedef int DataType;
typedef struct SeqList
{
	DataType *data;		//数据域
	int sz;						//有效个数
	int capacity;				//容量
}SeqList, *pSeqList;

       与静态顺序表不同的地方在于,由于顺序表是动态的,因此没有最大容量,顺序表的容量表示的是当前容量。当容量不足时,会调用扩容函数,对顺序表进行扩容。同时,顺序表的容量为扩容后的容量。
       对于动态顺序表来说,需要实现的功能基本也包括:顺序表的初始化、销毁、插入数据、删除数据、查找数据等,下面一一进行实现。

顺序表的初始化:

//动态顺序表的数据域是动态分配的空间,因此它的表示使用指针实现的
//初始化时,开辟空间的大小为定义的默认空间的大小。
void InitSeqList(pSeqList ps)
{
	assert(ps);				//确保ps的有效性
	ps->data = (DataType *)malloc(DEFAULT_CAPACITY * sizeof(DataType));
	if (ps->data == NULL) {			//检测开辟空间是否成功
		perror("error foe Initialize");
		exit(EXIT_FAILURE);
	}
	ps->sz = 0;
	ps->capacity = DEFAULT_CAPACITY;          //容量的大小为默认容量的大小
}

顺序表的销毁:

//由于动态顺序表的空间是动态申请的,因此在程序结束时,需要对申请的空间进行释放。
void DestroySeqList(pSeqList ps)
{
	assert(ps != NULL);				//确保ps有效
	free(ps->data);					//释放空间
	ps->data = NULL;				//释放后 data 指向的空间不再属于它,因此需要进行释放
	ps->capacity = 0;					//置空间为0
	ps->sz = 0;							//有效数据个数为0
}

顺序表的插入:

       动态顺序表的插入与静态顺序表原理相同,也有三种。这里以尾插为例进行说明。
在这里插入图片描述
       通过上面的对比可以看出,在动态顺序表中,当需要插入元素时,首先进行容量检查。若顺序表已满,则进行扩容,当扩容结束后,再进行元素的插入。若顺序表未满,则直接插入。函数CheckCapacity即用来检测容量以及扩充容量。


void CheckCapacity(pSeqList ps)     //检测空间是否占满,若满,则扩容
{
	if (ps->sz < ps->capacity) {       //如果当前有效元素个数小于顺序表容量 
		return;									  //则不进行其他操作,直接退出。
	}												 
//否则,进行扩容。新的空间大小为 : 当前容量 + 默认增加的个数
//如果realloc函数开辟空间失败,返回的是NULL。
//为了防止扩容失败而导致原顺序表丢失,因此,先用一个临时变量进行扩容,当扩容成功后再进行赋值。
	DataType *tmp = (DataType *)realloc(ps->data, sizeof(DataType) * (ps->capacity + DEFAULT_ADD));
	if (tmp == NULL) {					//检测扩容是否成功
		perror("error for realloc");
		exit(EXIT_FAILURE);
	}
	ps->data = tmp;						//顺序表指针指向新的空间
	ps->capacity += DEFAULT_ADD;		//扩容后的容量为当前容量 + 默认增加的个数
}

//头插
void PushFront(pSeqList ps, DataType d)
{
	int i = 0;
	assert(ps != NULL);
	CheckCapacity(ps);
	for (i = ps->sz; i > 0; i--) {
		ps->data[i] = ps->data[i - 1];
	}
	ps->data[0] = d;
	ps->sz++;
}

//给定元素插入
void Insert(pSeqList ps, int pos, DataType d)
{
	int i = 0;
	assert(ps != NULL);
	if (pos < 0 || pos > ps->sz) {
		printf("插入位置错误!\n");
		return;
	}
	CheckCapacity(ps);
	for (i = ps->sz; i > pos; i--) {
		ps->data[i] = ps->data[i - 1];
	}
	ps->data[pos] = d;
	ps->sz++;
}

顺序表的查找

       动态顺序表的查找与静态顺序表的查找相同,

//顺序表的查找只需要像数组查找元素一样遍历数组即可
//如果找到了返回元素所在位置的下标,如果找不到那么返回-1
int Find(pSeqList ps, DataType d)
{
	int i = 0;
	assert(ps != NULL);
	for (i = 0; i < ps->sz; i++) {
		if (ps->data[i] == d) {
			return i;
		}
	}
	printf("\nNOT FOUND! \n");
	return -1;
}

       顺序表的查找还可以用二分查找的方式来做,由于二分查找的前提是有序,因此首先需要对顺序表进行排序。

void Sort(pSeqList ps)
{
	int flag = 0;
	int i = 0;
	int j = 0;
	for (i = 0; i < ps->sz - 1; i++) {
		for (j = 0; j < ps->sz - i - 1; j++) {
			if (ps->data[j] > ps->data[j + 1]) {
				DataType tmp = ps->data[j];
				ps->data[j] = ps->data[j + 1];
				ps->data[j + 1] = tmp;
				flag = 1;
			}
		}
		if (flag == 0) {
			break;
		}
	}
}

int BinarySearch(pSeqList ps, DataType d)
{
	int mid = 0;
	int left = 0;
	int right = ps->sz - 1;
	assert(ps != NULL);
	while (left <= right)
	{
		mid = left + ((right - left) >> 1);
		if (d < ps->data[mid]) {
			right = mid - 1;
		}
		else if (d > ps->data[mid]) {
			left = mid + 1;
		}
		else {
			return mid;
		}
	}
	return -1;
}

顺序表的删除

       动态顺序表的删除也与静态顺序表相同:

//头删
void PopFront(pSeqList ps)
{
	int i = 0;
	assert(ps != NULL);
	if (ps->sz == 0) {
		return;
	}
	for (i = 0; i < ps->sz - 1; i++) {
		ps->data[i] = ps->data[i + 1];
	}
	ps->sz--;
}

//尾删
void PopBack(pSeqList ps)
{
	if (ps->sz == 0) {
		return;
	}
	ps->sz--;
}

//删除首个指定元素
void Remove(pSeqList ps, DataType d)
{
	int i = 0;
	assert(ps != NULL);
	i = Find(ps, d);
	if (i == -1) {
		printf("CAN'T REMOVE");
		return;
	}
	for (; i < ps->sz - 1; i++) {
		ps->data[i] = ps->data[i + 1];
	}
	ps->sz--;
}

//删除所有指定元素
void RemoveALL(pSeqList ps, DataType d)
{
	int i = 0;
	int j = 0;
	assert(ps != NULL);
	for (i = 0; i < ps->sz; i++) {
		if (ps->data[i] != d) {
			ps->data[j] = ps->data[i];
			j++;
		}
	}
	ps->sz = j;
}

最后是顺序表的几个状态函数:

//顺序表元素个数
int SeqList_Size(const pSeqList ps)
{
	return ps->sz;
}
//顺序表是否为空
bool SeqListEmpty(const pSeqList ps)
{
	return ps->sz == 0;
}

//顺序表是否满
bool SeqListFull(const pSeqList ps)
{
	return ps->sz == ps->capacity;
}

以上即是本篇所有内容,不足之处还望指正。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值