数据结构之线性表1:顺序表

线性表定义和特点

具有相同类型的数据元素的有限序列

初始结点有后继无前驱,终端结点有前驱无后继,中间结点,内部结点有且仅有一个直接前驱和一个直接后继。

归结为:关系线性化,结点顺序存

内存分配函数

使用以下函数需要加载头文件<stdlib.h>

  1. malloc(m)函数:分配m个字节的地址空间,并返回这段空间的首地址
  2. sizeof(x)函数:计算变量x的长度
  3. free§:释放指针p所指变量的存储空间,即彻底删除一个变量

例如:L.data=(int*)malloc(sizeof(int)*MaxSize)

通过sizeof函数计算int型占4个字节,再乘以最大结点个数MaxSize,通过malloc分配4*MaxSize个空间。

假如MaxSize=100,这时我们知道了需要400个字节,但是不知道是400个char,还是100个int或者50个double,所以在前面要加强制类型转换(int)说明是整形,当data是指针的时候就(int*)说明是指向整形的指针。

常用预定义变量

顺序表示和实现

逻辑连续的同时存储也连续。任一元素可以随意存取,不需要一个一个遍历过去。但是插入和删除运算不方便,除了表尾元素操作外,其他位置都需要移动大量元素。

存储分配职能预先进行静态分配,因此表长变化较大时,难以确定合适的存储规模,且长度不可动态定义。

元素存储位置的计算

存储类型描述

由于增删不太方便,我们在定义线性表每个结点的同时,还需要保存当前的表长。

ElemType是替代“int”,“float”,“char”等数据类型…

#define maxsize 100		//宏定义线性表能达到的最大长度
typedef struct{
	ElemType elem[maxsize];	//存放线性表内存放的数据元素(每个结点)
    int length;		//记录当前线性表中元素个数
}seqlist;
seqlist L;
L.data=(ElemType*)malloc(sizeof(ElemType)*10)

此处elem是有100个结点的数组,length是当前表长,这个顺序表类型名(我称之为“表型”)是seqlist,即表内含有100个结点。

使用seqlist Lseqlist *L就创建了:名为L,类型为seqlist的顺序表

  1. 最基本的结构体
typedef struct{
	int data[10];//十个结点 
	int length;//元素个数即表长 
}seqlist;
seqlist L;

由于声明了结点个数,因此不需要申请内存分配。

  1. 如下图这种每个结点内两个元素

    先声明一个类型,再嵌套进别的结构体内使用
typedef struct{
	float p;	//系数
    int e;	//阶数
}poly;//定义这种存系数+阶数的类型叫poly

typedef struct{
	poly *elem;	
    /*使用上面声明的类型去定义顺序表首地址,动态定义首地址(也可以使用 poly elem[100],静态定义)*/
    int length; //表长
}seqlist;		//仅声明变量时还不分配空间

seqlist L;
L.elem=(poly*)malloc(sizeof(ElemType)*MaxSize)	//需要给结点分配空间

查找操作

按值查找并返回位置

一个一个对比,使用flag标志决定查没查到

int locate(seqlist L,int find){	//查找某个数字,返回下标 
	int i,number;
	int flag=0;
	for(i=0;i<L.length;i++){	
		if(L.data[i]==find){
			flag=1;
			number=i+1;
		}
	}
	if(flag==1)	
		return number;
	else
		return -1;		
}

算法分析

查找次数和关键字位置有关,平均查找长度类似数学中的期望:

每个被查找到的概率都是1/n,化简后是 (n+1)/2

插入操作

插入元素到某个位置之前(挤开,占用原有位置)

关键:

  1. 插入位置之后的元素,依次后移一位腾出位置,然后插入。
  2. 检查插入位置,满足情况:在下标>0且下标<表长+1
  3. 检查表长,若表长==MaxSize,则不能插入
  4. 插入快结束时,给表长+1
seqlist add(seqlist L,int local,int num) //在local位置插入数字num 
{
	int i,j;
	if((local<1)||(local>L.length+1)){
		printf("\n输入位置不合法");				//插入位置不合法 
	}
	else if(L.length==MaxSize){
		printf("\n插入位置不够");				//位置满了 
	}
	else{
		for(i=L.length-1;i>=local-1;i--){		
        /***从最大下标length+1到目标下标local,并 包含 目标下标,向后赋值 ***/
			L.data[i+1]=L.data[i];
		}
		L.data[local-1]=num;	//定位赋值 
	}
	L.length++;

	printf("\n");
	for(i=0;i<L.length;i++){		//打印检查 
		printf("%d ",L.data[i]);
	}
}

该代码存在变量传递问题,即在函数接收不到插入结果

删除操作

删除第i个位置的元素

关键:

  1. 检查插入位置,满足情况:在下标>0且下标<表长+1

  2. 删除本位置元素,后面依次前移一位补上位置

  3. 插入快结束时,给表长-1

seqlist del(seqlist L,int local){//删除local位置的元素 
	int i;
	if(local>L.length||local<1)
		printf("\n输入位置无元素");
	else{
		for(i=local-1;i<L.length;i++){
			L.data[i]=L.data[i+1];		//删除元素之后的元素前移
		}
	}
	L.length--;

	printf("\n");
	for(i=0;i<L.length;i++){		//打印检查 
		printf("%d ",L.data[i]);
	}

}

算法分析

每个元素被选中概率1/n,移动次数之和:(n-1)n/2,最后得到的删除期望: (n-1)/2

合并操作

为适用西北大学耿国华教授讲解,将结构体进行一些修改(也可以不修改,将下标last用表长length-1表示):

typedef struct{
	int data[10];
	int last;
}seqlist;

合并操作其实就是两个顺序表中较小的优先排入新顺序表,当有一个表使用结束后,另一个表全部排入新表。(此处默认递增顺序)

/*	i,j,k分别指向L1,L2,L3 */
while(i<=L1.last&&j<=L2.last){ 
		if(L1.data[i]<=L2.data[j])	//哪个小就把哪个放进新线性表里
		{
			L3.data[k]=L1.data[i];
			i++;
			k++;
		}
		else{
			L3.data[k]=L2.data[j];
			j++;
			k++;
		}
}
	
while(i<=L1.last){		//若i仍没有结束,则将L1全部放进L3
		L3.data[k]=L1.data[i];
		i++;
		k++;
} 

while(j<=L2.last){
		L3.data[k]=L2.data[j];
		j++;
		k++;
} 

摘自: 王卓老师:https://www.bilibili.com/read/cv3285768

摘自:耿国华老师 https://www.bilibili.com/video/BV1kx411h7pF?p=10

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值