数据结构—顺序表

先语:前面记录了怎么评判算法好坏的时间复杂度,空间复杂度。下面正式记录一个数据结构,顺序表。在说顺序表的时候,先来说说线性表。因为顺序表属于线性表。线性表通俗的说,就是一根线一样,一连串的。这是逻辑上的。物理存储上的并不是像数组一样一连串的内存空间啊。当然也有物理上是连续的 就是下面要说的顺序表,

线性表(linear list)

  •      概念

    n个具有相同特性的数据元素的有限序列。(和数组有点像)

  •      分支

  1. 顺序表
  2. 链表
  3. 队列

    (当然这里只是列举了常见的。)

正式有请——

顺序表

  •        概念

    一段物理地址连续的存储单元依次存储数据元素的线性结构。一般情况写采用数组存储。

(一看到数组是不是就觉得没那么高大上了呢?其实不只只是数组嘿)

  •        分类

       1、  静态顺序表

//C语言
#define N 100    //静态的,必须先规定容量

typedef struct SeqListnode
{
    int arr[n];
    int size;        //有效的数据个数
}SeqL;

     2 、动态顺序表

typedef strcut SeqListnode    
{
    int* arr;
    int size;       //有效个数 
    int maxcap;    //容量
}SeqL;
  •        实现

“纸上得来终觉浅,绝知此事要躬行。”所以现在来写写。因为静态顺序表我们用的并不多,而且数组的个数都是规定好了的。要么存在长度太小存不下,要么长度太大,浪费内存。所以,下面记录的是动态顺序表。一方面,它有点难,另一方面,用的相对较多。看我博客的前辈或道友们,如果如果下面的代码有什么问题,还请不吝赐教。直接上代码。

//C语言
typedef struct SeqList {
	int* arr;
	size_t size;
	size_t maxNum;
}Sql;
//先创建一个表。这个表有一个 int 指针,还有一个有效个数的 size,还有一个最大个数容量的maxNum

//下面初始化。结构体前面学过哈。
void sql_init(Sql* sl, size_t maxnum) 
{
	assert(sl != NULL);    //先检查用户传来的是不是空表。
	sl->arr = (int*)malloc(sizeof(int)*maxnum);    //给数组动态分配一个内存
	sl->maxNum = maxnum;
	sl->size = 0;        //开是没有数据,所以size = 0;
}

void sql_destroy(Sql* sl)
{
	assert(sl != NULL);
	sl->arr = NULL;        //数组置空
	sl->maxNum = sl->size = 0;        //有效数字和最大容量置空
}

void print_arr(Sql* sl)
{
	assert(sl != NULL);
	for (size_t i = 0; i < sl->size; i++)    //遍历数组
	{
		printf("%d ",sl->arr[i]);
	}
	printf("\n");
}

//扩容接口
void check_maxNum(Sql* sl) 
{
	assert(sl != NULL);
	if (sl->size==sl->maxNum)
	{
		printf("正在扩容……\n");
		sl->maxNum *= 2;        //最大容量扩大一倍
		int* newarr = (int*)malloc(sizeof(int)*sl->maxNum);    //开辟一个新的数组
		for (size_t i = 0; i < sl->size; i++)        //存储老数组的数据
		{
			newarr[i] = sl->arr[i];
		}
		free(sl->arr);        //释放老数组的内存
		sl->arr = newarr;     //搬运数据
                free(newarr);         //释放掉不用的新的数组
		printf("扩容成功");
	}
}

这里创建了一个初始的表。里面的参数是这个样子的。得注意,这是size个数据,数组的下标是从 0 开始的。所以数组下标是 0 ~ size -1;

    我们把服务用的函数都写好了。其实也可以叫接口。这里呢没有写头文件。服务就是准备开始。或者救灾救难的。比如扩容的啊,初始化啊。在代码里面有详细的注释交代。因为边看到代码 便看注释,比较好。如果代码的可读性不好,一看注释就好了。不罗嗦了。下面是顺序表的操作,增删查改

//C语言

//查寻接口
//返回的是下标
int sql_find(Sql* sl, int num)
{
	assert(sl != NULL);        //还是检查是不是传进来一个空表
	for (size_t i = 0; i < sl->size; ++i)    //size: 有效的个数
	{
		if (num==sl->arr[i])        //比较是否数据相同
		{
			return i;        //相同返回下标
		}
	}
	return -1;        //没找到返回 -1;别写 return 0,因为这就返回第 0 个下标的数据 
}


//修改某一位置的数据
void sql_updata(Sql* sl, size_t pos, int num)
{
	assert(sl != NULL);
	sl->arr[pos] = num;    //直接覆盖该下标的数据,完成修改
}


//增接口
	//头插
void sql_add_front(Sql* sl, int num)
{
	assert(sl != NULL);
	for (size_t add = sl->size; add > 0; add--)
	{
		sl->arr[add] = sl->arr[add - 1];    //用第 size 的空间存储 第size - 1的数据,进行循环。实现数据的后移,这样第一个位置就腾出来了。
	}
	sl->arr[0] = num;    //给第一个下标赋值
	++sl->size;        //插入数据了,就要把有效个数加 1 了。
}
	//尾插
void sql_add_end(Sql* sl, int num)
{
	assert(sl != NULL);
	sl->arr[sl->size] = num;    把第size下标直接赋值
	++sl->size;
}
	//随机加入
void sql_add_rand(Sql* sl, size_t pos, int num)
{
	assert(sl != NULL);
	for (size_t i = sl->size; i > pos; i--) //这里和头插差不多。只是把头插的位置换成我们想要的位置就行。
	{
		sl->arr[i] = sl->arr[i-1];
	}
	sl->arr[pos] = num;
	++sl->size;
}

 

//C语言
//删接口
	//头删
void sql_del_front(Sql* sl)
{
	assert(sl != NULL);
	for (size_t del = 0; del < sl->size-1; del++)    //删除就覆盖
	{
		sl->arr[del] = sl->arr[del + 1];       
                         //头删要从从第二个数覆盖第一个数开始,
                        //第三个覆盖第二个。依次覆盖.直到最后一个属覆盖倒数第二个
	}
		--sl->size;    //删除完成,有效个数就要减少1
}

	//尾删
void sql_del_end(Sql* sl)
{
	assert(sl != NULL);
	sl->arr[sl->size - 1] = sl->arr[sl->size];    //把最后下标的数直接覆盖就行了。
	--sl->size;        //删除完成,有效个数就要减少1
}
	//随机删除
void sql_del_randpos(Sql* sl, size_t pos)    //这是随机位置删除
{
	assert(sl != NULL);
	for (size_t i = pos; i < sl->size; i++)    //把头删改一下,就行了。仔细对比
	{
		sl->arr[pos] = sl->arr[pos + 1];
	}
	--sl->size;    //删除完了,一定要记得--size啊。
}
void sql_del_randnum(Sql* sl, int num)    //这是删除第一个遇见的数。如,数组中
                                          //有 不知一个 num ,就删除下标最小的 num
{
	assert(sl != NULL);
	int pos = sql_find(sl, num);
	sql_del_randpos(sl, pos);
}

//C语言
//拓展
	//冒泡排序
void sql_bubblesort(Sql* sl)    //冒泡排序就不多说了。
{                                //主要是参数的替换。换成结构体里的参数
	assert(sl != NULL);
	for (size_t i = 0; i < sl->size; i++)
	{
		int con = 1;
		for (size_t j = 0; j < sl->size - i - 1; j++)
		{
			if (sl->arr[j] > sl->arr[j+1])    //产生交换
			{
				int temp = sl->arr[j];
				sl->arr[j] = sl->arr[j + 1];
				sl->arr[j + 1] = temp;
				con = 0;
 			}
		}
		if (con == 1)    //这是优化程序的语句
		{
			return;    //如果 没有产生交换,说明已经排序好了,就可以退出循环了
		}
	}
}
	
    //折半查找
int sql_half_find(Sql* sl, int num)
{
	assert(sl != NULL);
	int left = 0;
	int right = sl->size;
	while (left < right)    //这里只有取等和不取等要细说一下,就是 
                                    //left < right / left =< right
                                    //上个博客介绍了折半查找,以前也写过栗子
        //简单的说就是,取等的话,right == size - 1
        //不取等就是    right == size 
	{
		int mid = (left + right) / 2;
		if (sl->arr[mid]==num)
		{
			return mid;
		}
		else if (sl->arr[mid] < num)
		{
			left = mid + 1;
		}
		else
		{
			right = mid;
		}
	}
	return -1;
}    

    //删除相同的数

    //意思就是删除数组中与 num 相同的所有的数
void sql_del_allsame(Sql* sl, int num)
{
	assert(sl != NULL);
	int notsame = 0;
	for (size_t i = 0; i < sl->size; i++)
	{
		if (sl->arr[i]!=num)	//这里就是如果没有遇见就把值继续放在原来的下标下面。
		{
			sl->arr[notsame++] = sl->arr[i];
		}        //遇见的话,就不管,直到遇见不等于 num 的数,把这个数覆盖到 num 上
		
	}
	sl->size = notsame; //画图来解释

    现在把这个删除相同的数用图来表示。方便理解

终于把这个画完了,有点啰嗦,但是好理解啊。

结尾

到这儿顺序表介绍完毕。欢迎评价和指出错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值