(数据结构)顺序表操作——C实现

线性表的顺序表示指的是用一组地址连续的存储单元(内存)依次存储线性表的数据元素。
特点

  1. 逻辑相邻,物理也相邻
  2. 支持存放,插入,删除,修改,读取数据等操作
  3. 一位数组是一种特殊的顺序表,但顺序表不是数组
  4. 插入和删除较链表来说不太方便

固定大小的顺序表

结构设计

#define SEQ_INIT_SIZE 10
typedef int ElemType;

typedef struct 
{
	ElemType data[SEQ_INIT_SIZE];
	int cursize;
}SeqList;

//注意区别
//无名结构体所定义的全局结构体变量
struct
{
	ElemType data[SEQ_INIT_SIZE];
	int cursize;
} SeqList;

缺陷:

  1. 不能够随着数据量的增多而增大数组大小
  2. 受到栈空间的限制,不能超过1M

可变顺序表

顺序表的结构设计

typedef struct SeqList
{
	int* data;
	int cursize;
	int capacity;
}SeqList;

其他参数

typedef SqList * PSqList;//

#define INIT_SIZE 10 //初始化大小
#define TRUE  1
#define FALSE 0
#define OK    1
#define ERROR 0

#define INFEASIBLE -1//不能实行
#define OVERFLOW -2  //内存溢出

typedef int status;

顺序表操作

初始化

void InitSqList(PSqList ps)
{
	assert(ps != NULL);
	ps->elem = (int *)malloc(INIT_SIZE*sizeof(int));
	ps->length = 0;
	ps->listsize = INIT_SIZE;
}

判满,内部函数,不对外

用户不需要在意满还是没满,只是使用,因此加上“static”关键字

static bool IsFull(PSeqList ps)
{
	return GetSize(ps) == GetCapacity(ps);
}

扩容,将总容量扩大到原来的2倍

static bool Inc(PSeqList ps)
{
	assert(ps != NULL);
	ElemType* newdata = NULL;
	int total = ps->capacity * SEQ_INC_SIZE;
	newdata = (ElemType*)malloc(sizeof(ElemType) * total);
	//这里没有使用realloc的原因是:
	//一旦数据量过大堆区空间不足,realloc将返回空指针,接收后原数据会被丢失
	
	if (NULL == newdata)
	{
		return false;
	}

	memcpy(newdata, ps->data, sizeof(ElemType) * ps->capacity);
	free(ps->data);
	ps->data = newdata;
	ps->capacity = total;
	return true;
}

插入

status Insert(PSeqList ps, int pos, int val)
{
	assert(ps != NULL);

	if (pos < 0 || pos > ps->cursize)//cursize插入仍连续后面就不行了
	{
		return INFEASIBLE;//不能实行
	}
	if (IsFull(ps) && !Inc(ps))
	{
		return OVERFLOW;
	}
	for (int i = ps->cursize; i > pos; i--)
	{
		ps->data[i] = ps->data[i - 1];
	}
	ps->data[pos] = val;
	ps->cursize += 1;
	return OK;
}

按值查找

/按值查询
int FindValue(PSeqList ps, ElemType val)
{
	assert(ps != NULL);
	//顺着遍历
	//int pos = -1;
	// for(int i = 0;i<ps->cursize;i++)
	// {
	// 	if(val == ps->data[i]);
	// 	{
	// 		pos = i;
	// 		break;
	// 	}
	// }

	//倒着遍历
	int pos = ps->cursize - 1;
	while (pos >= 0 && ps->data[pos] != val)//减小到-1,简洁与不做判断直接退出返回-1,正确
	//注意错误代码:
	//while( ps->data[pos] != val && pos >= 0),减小到-1,先判断前一句会产生数组上越界
	{
		--pos;
	}
	return pos;
}

### 按值删除

```c
bool DeleteVal(PSqList ps,int key)
{
	int i = Search(ps,key);
	if(i < 0)//没有key
	{
		return false;
	}

	return DeletePos(ps,i);
}

按下标删除

bool DeletePos(PSqList ps,int pos)
{
	if(pos<0 || pos>=ps->length)
	{
		return false;
	}

	//将后面的数据前移
	for(int i=pos;i+1<ps->length;i++)
	{
		ps->elem[i] = ps->elem[i+1];
	}

	//有效数据个数--
	ps->length--;

	return true;
}

删除所有重复的值

两个下标,且该算法时间复杂度为O(n)

//删除所有重复的值
void Remove_all(PSeqList ps,ElemType val)
{
	assert(ps != NULL);
	int j = -1;
	for(int i = 0;i<ps->cursize;++i)
	{
		if(ps->data[i] != val)
		{
			j++;
			ps->data[j] = ps->data[i];
		}
	}
	ps->cursize = j+1;
}

获取指定位置的值

(注意这里容易出现的问题:)
1.设计问题:很多人会设计成int GetElem(PSqList ps,int pos),返回错误值一定会和某一个正常值冲突无法区分。
2.成功返回true,失败返回false.成功的值通过rtval(输出参数)带出

bool GetElem(PSqList ps,int pos,int *rtval)
{
	if(pos<0 || pos>=ps->cursize)
	{
		return false;
	}

	*rtval = ps->data[pos];
	return true;
}

修改

bool SetElem(PSqList ps,int pos,int newVal)
{
	if(pos<0 || pos>=ps->cursize)
	{
		return false;
	}

	ps->data[pos] = newVal;

	return true;
}

排序

//冒泡排序
void BubbleSort(PSeqList ps)
{
	assert(ps != NULL);
	int n = ps->cursize;
	for(int i = 1;i<n;++i)//控制比较的轮次,每一次都将最大的那个放到最后,并不再下次比较的名单中
	{
		for(int j = 0;i<n-i;j++)
		{
			if(ps->data[i]>ps->data[j+1])
			{
				Swap_val(&ps->data[i],&ps->data[j+1]);
			}
		}
	}
}

合并两个有序顺序表

//合并两个有序顺序表
void  MergeList_sq(const PSeqList la,const PSeqList lb,PSeqList lc)
{
	ElemType* pa = la->data;
	ElemType* pb = lb->data;
	lc->capacity = la->cursize + lb->cursize;
	ElemType * pc = lc->data = (ElemType*)malloc(sizeof(ElemType)*lc->capacity);
	if(NULL == lc->data)exit(EXIT_FAILURE);

	ElemType* pa_last = la->data + la->cursize-1;
	ElemType* pb_last = lb->data + lb->cursize-1;

	while(pa <= pa_last && pb <= pb_last)
	{
		if(*pa <= *pb)
		{
			*pc++ = *pa++;//*pc = *pa pc++  pa++
		}
		else
		{
			*pc++ = *pb++;
		}
	}

	while(pa<= pa_last){*pc++ = *pa++;}//a表没插完
	while(pb<= pb_last){*pc++ = *pb++;}//b表没插完
}

获取有效数据个数

int GetLength(PSqList ps)
{
	return ps->cursize;
}

判空

道理跟清除一个字符串(首字符修改\0,就无法读取该字符串达到删除目的)一样

bool IsEmpty(PSqList ps)
{
	return ps->cursize== 0;
}

清空

//置空
void Clear(PSeqList ps)
{
	assert(ps != NULL);
	ps->cursize = 0;
}

销毁,回收内存

void Destroy(PSeqList ps)
{
	assert(ps != NULL);
	free(ps->data);
	ps->data = NULL;
	ps->cursize = 0;
	ps->capacity = 0;
}

输出

//打印
void Printseqlist(const PSeqList ps)
{
	assert(ps != NULL);
	printf("Now Capacity : %d\n", ps->capacity);
	printf("Now Cursize : %d\n", ps->cursize);
	for (int i = 0; i < ps->cursize; i++)
	{
		printf("%d ", ps->data[i]);
	}
	printf("\n");
}

总结

顺序存储结构

适用场景:适用于需要大量随机访问数据元素的场景,增删数据元素较少的程序

  1. 支持随机访问
  2. 尾插尾删效率高

不适用的场景

  1. 头插头删、中间插入、删除效率低、不适合这些位置的插入删除
  2. 增容代价高:申请、拷贝、释放

头文件sqlist.h

#pragma once //防止头文件被重复引用
//头文件,存放结构的定义和函数的声明
#define SEQ_INIT_SIZE 2 //初始化大小
#define SEQ_INC_SIZE 2
typedef int ElemType;
typedef int status;

typedef struct SeqList
{
	int* data;
	int cursize;
	int capacity;
}SeqList;

typedef SeqList* PSeqList;

//初始化
void InitSeqList(PSeqList ps);

//在ps的pos位置,插入数据val
status Insert(PSeqList ps, int pos, int val);

//尾插
void Push_Back(PSeqList ps, int val);

//头插
void Push_Front(PSeqList ps, int val);

//获取有效数据个数
int GetSize(const PSeqList ps);

//获取顺序表容量
int GetCapacity(const PSeqList ps);

//判空
static bool IsEmpty(const PSeqList ps);

//判满
static bool IsFull(const PSeqList ps);

//扩容
static bool Inc(PSeqList ps);

//按值查询
int FindValue(const PSeqList ps, ElemType val);

//按下标删除
bool DeletePos(PSeqList ps,int pos);

//按值删除
bool DeleteVal(PSeqList ps,int val);

//删除所有重复的值
void Remove_all(PSeqList ps,ElemType val);

//修改数据
bool SetElem(PSeqList ps,int pos, int newval);

//清空数据
void Clear(PSeqList ps);

//销毁
void Destroy(PSeqList ps);

//置空
void Clear(PSeqList ps);

//输出
void Printseqlist(const PSeqList ps);

//交换
void Swap_val(ElemType *a,ElemType *b);

//冒泡排序
void BubbleSort(PSeqList ps);

//合并两个有序顺序表
void  MergeList_sq(const PSeqList la,const PSeqList lb,PSeqList lc);

#endif
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值