数据结构——线性表

本文详细介绍了线性表的概念和操作,包括静态分配和动态分配实现的顺序表,单链表、双链表、循环链表的定义、插入、删除、查找等操作。此外,还探讨了静态链表的特点和应用场景,并对比了顺序表与链表的优缺点。
摘要由CSDN通过智能技术生成

目录

1.线性表的定义与操作

2.顺序表

2.1顺序表的定义

2.1.1静态分配实现顺序表

 2.1.2动态分配实现顺序表

2.2顺序表的插入和删除

2.2.1顺序表的插入

2.2.2顺序表的删除

2.3顺序表的查找

2.3.1按位查找

2.3.2按值查找

3.单链表

3.1单链表的定义

3.1.1定义与重命名

3.1.2单链表初始化  

3.2单链表的插入和删除

3.2.1插入

3.2.2删除

3.3单链表的查找

3.3.1按位查找(带头结点)

3.3.2按值查找

3.3.3求表长

3.4单链表的建立

3.4.1尾插法

3.4.2头插法

4.双链表

4.1初始化

4.2插入

4.3删除(后删)

4.4遍历

5.循环链表

5.1循环单链表

5.2循环双链表

6.静态链表

6.1概念

6.2定义与声明

6.3基本操作实现思路

7.顺序表VS链表

7.1逻辑结构和物理结构(存储结构)的比较

7.2基本操作的比较

1.线性表的定义与操作

LinearList(线性表)的部分数据运算:

Initsist(&L)//初始化表
DestroyList(&L)//销毁操作

ListInsert(&L,i,e)//插入操作。在表L第i个位置(位序)插入元素e
ListDelete(&L,i,&e)//删除操作。删除表L第i个位置,用e返回删除元素的值 

LocateElem(L,e)//按值查找
GetElem(L,i)//按位查找(位序) 

Length(L)//求表长
PrintList(L)//输出操作,打印表
Empty(L)//判空操作 。L空——true 

所有命名都采用驼峰命名法 

2.顺序表

2.1顺序表的定义

2.1.1静态分配实现顺序表

sequence list

分配的存储空间大小为:MaxSize*sizeof(ElemType)

#define MaxSize 10
typedef struct{
	ElemType data[MaxSize];//用静态数组存放数据元素 (于存储空间是静态的,表长刚开始确定后就无法更改)
	int length;
}SqList; 

没有设置数据默认值时违规打印顺序表时,出现了脏数据

静态分配实现过程:

#include <stdio.h> 
#define MaxSize 10
typedef struct{
	int data[MaxSize];//用静态数组存放数据元素 (由于存储空间是静态的,表长刚开始确定后就无法更改)
	int length;
}SqList; 
void InitList(SqList &L){
	L.length = 0;//初始化顺序表表长为0 
}
void PrintList(SqList L){
	int i;
	for(i=0;i<L.length;i++){ //其实这里用L.length访问元素也是不友好的 而是用GetELEM(L)这一基本操作来访问各个数据元素 
		printf("data[%d] =  %d\n" , i , L.data[i]);
	} 
}
int main(){
	SqList L;
	InitList(L);
	//...
	PrintList(L);	
}

 2.1.2动态分配实现顺序表

#define InitSize 10
typedef struct{
	ElemType *data;//指示动态分配数组的指针 
	int  MaxSize; //顺序表最大长度 
	int length;//顺序表当前长度 
}SeqList; 

//C——malloc free 函数 stdlib.h中有定义 
L.data = (ElemType*) malloc(sizeof(ElemType) * InitSize);//分配连续的内存空间  要强制转换类型 
//C++——new delete 关键字 

//eg 申请分配10个int型数据的一片连续空间(10*4B),并用L.data返回该存储空间的首地址(指针),并对该指针强转 
L.data = (int*) malloc(sizeof(int) * InitSize); 

动态分配实现过程: 

#include <stdlib.h>//mallo free 函数的头文件 
#define InitSize 10
//顺序表的定义
typedef struct{
	int *data;//指示动态分配数组的指针 
	int MaxSize; //顺序表最大长度 
	int length;//顺序表当前长度 
}SeqList; 

//初始化操作
void InitList(SeqList &L){
	L.data = (int*) malloc(sizeof(int) * InitSize); //用malloc申请一篇连续空间 (动态数组) 
	L.length = 0;
	L.MaxSize = InitSize; 
}

//增加动态数组长度的操作
void IncreaseList(SeqList &L,int len){
	//step1:用p指向原存储空间
	int *p = L.data;
	//step2:用L.data指向malloc开辟InitSize+len的新空间
	L.data = (int*) malloc(sizeof(int) * (InitSize+len)); 
	//step3:原空间向新空间复制(时间开销很大) 
	for(int i=0;i<L.length;i++){
		L.data[i] = p[i];//依然可以用下标法访问 
	} 
	//step4:修改L.MaxSize
	L.MaxSize = L.MaxSize+len; 
	//step5:释放p
	free(p);  
}

int main(){
	SeqList L;//声明一个顺序表 存储了*data length MaxSize 三个变量
	InitList(L);
	//...
	IncreaseList(L,5);//增加动态数组的长度 
	
}

2.2顺序表的插入和删除

2.2.1顺序表的插入

示例:在表L的第3个位置插入元素9 

#include<stdio.h>
#define MaxSize 5 
typedef struct{
	int data[MaxSize];
	int length;
}SqList;
 
void InitList(SqList &L){
	L.length = 0;
}

bool ListInsert(SqList &L,int i,int e){//在表L的第i个位置插入元素e 
//step1、2使算法更具有健壮性 
	
//	//step1:存储空间满的判断 
//	if(L.length>=MaxSize){
//		printf("L is full\n");
//		return false;
//		
//	}
//	//step2:插入的合法性判断,0<i<=length时有效
//	if(i<1 || i>L.length+1){
//		printf("invalid i\n"); 
//		return false; 	
//	}
	//step1:存储空间满的判断 
	if(L.length>=MaxSize)
		return false;
	//step2:插入的合法性判断,0<i<=length时有效
	if(i<1 || i>L.length+1)
		return false; 	
		
	//step3:从尾部(length-1的位置)移
	for(int j=L.length;j>=i;j--){
		L.data[j] = L.data[j-1];
	}
	//step4:插
	L.data[i-1] = e;
	//step5:改(表长+1) 
	L.length++; 
	return true; 
}
void PrintList(SqList L){
	printf("L中数据如下:\n");
	for(int i=0;i<L.length;i++){ //其实这里用L.length访问元素也是不友好的 而是用GetELEM(L)这一基本操作来访问各个数据元素 
		printf("data[%d] =  %d\n" , i , L.data[i]);
	} 
	printf("\n");
}

int main(){
	SqList L;
	InitList(L);
	for(int i=0,j=1;i<3;i++,j++){//原表数据是这样子的,先假设原先插入了3个数据 
		ListInsert(L,j,i);
	}
	
	printf("原表length:%d\n",L.length);
	PrintList(L);//未插入前打印一次 
	
	ListInsert(L,3,9);//在表L的第3个位置插入元素9
	PrintList(L);//插入后打印一次
//	错误示例 
//	ListInsert(L,9,9);//在表L的第3个位置插入元素9:invalid i
 
}

动态分配方式下的插入操作代码同上

插入操作算法时间复杂度:最好O(1);最坏O(N);平均O(N)

2.2.2顺序表的删除

示例:删除表中第2个元素,用变量e带回(所以用引用类型&)

bool ListDelete(SqList &L,int i,int &e){
	//step1:删除的合法性判断,0<i<=length时有效
	if(i<1 || i>L.length) return false;
	//step2:用e保留删除的元素,并返回
	e = L.data[i-1];
	//step3:从第i+1个向前移动
	for(int j=i;j<L.length;j++){
		L.data[j-1] = L.data[j]; 
	} 
	//step4:改(表长-1)
	L.length--; 
	return true;
}

int main(){
	SqList L;
	InitList(L);
	for(int i=0,j=1;i<3;i++,j++){//原表数据是这样子的,先假设原先插入了一些数据 
		ListInsert(L,j,i);
	}
	printf("原表length:%d\n",L.length);

	int e = -1;//???用e把删除的元素带回来 
	PrintList(L);//删除前打印一次
	ListDelete(L,2,e) ;//删除data[1] 
	printf("删除的元素是:%d\n",e);
	PrintList(L);//删除后打印一次
}

动态分配方式下的删除操作代码同上 

删除操作算法的时间复杂度:最好O(1);最坏O(N);平均O(N)

2.3顺序表的查找

2.3.1按位查找

静态分配方式下实现顺序表的按位查找 
示例:找到L第i个(位序)元素

#include<stdio.h>
#define MaxSize 10
typedef struct{
	int data[MaxSize];//静态分配方式下 
	int length;
}SqList; 

int GetElem(SqList L,int i){
	return L.data[i-1];//随机存取的优势 
} 

int main(){
	SqList L;
	int check_i = 3;
	InitList(L);
	for(int i=0,j=1; i<5 ;i++,j++){//假设表中原有5个数据 
		ListInsert(L,j,i);
	}
	PrintList(L);
	
	printf("查找到第%d个元素是:%d\n",checki,GetElem(L,check_i));
} 

动态分配方式下的按位查找操作代码同上,也是用下标法访问表中元素,代码如下:

#include<stdio.h>
#include<stdlib.h>
#define InitSize 10 
typedef struct{
	int *data;//静态分配方式下 
	int length;
	int MaxSize; 
}SqList; 
 
void InitList(SqList &L){
	L.data = (int*)malloc(sizeof(int)*InitSize);
	L.MaxSize = InitSize;
	L.length = 0;
}
bool ListInsert(SqList &L,int i,int e){
	if(L.length>= L.MaxSize) return false;
	if(i<1 || i>L.length+1) return false;
	
	for(int j=L.length; j>=i;j--){
		L.data[j] = L.data[j-1];
	}
	L.data[i-1] = e;
	L.length++;
	return true;
}
void PrintList(SqList L){
	printf("L中数据如下:\n");
	for(int i=0;i<L.length;i++){ //其实这里用L.length访问元素也是不友好的 而是用GetELEM(L)这一基本操作来访问各个数据元素 
		printf("data[%d] =  %d\n" , i , L.data[i]);
	} 
	printf("\n");
}
int GetElem(SqList L,int i){
	return L.data[i-1];//动态分配方式下也用下标法访问
} 
int main(){
	SqList L;
	int check_i = 3;
	InitList(L);
	for(int i=0,j=1; i<5 ;i++,j++){//假设表中原有5个数据 
		ListInsert(L,j,i);
	}
	PrintList(L);
	
	printf("查找到第%d个元素是:%d\n",checki,GetElem(L,check_i));
} 

按位查找时间复杂度:最好/最坏/平均:O(1)  //随机存取特性

2.3.2按值查找

 示例:查找L中值为e的元素,返回其位序 

#include<stdlib.h>
#include<stdio.h>
#define InitSize 10
typedef struct{
	int *data;
	int length;
	int MaxSize;
}SeqList;

//查找值为e的元素,返回其位序 
int LocateElem(SeqList L,int e){
	for(int i=0;i<L.length;i++){
		if(L.data[i] == e) return i+1;//注意位序和索引下标的关系 
	}
	return 0; 
}

int main(){
	SeqList L;
	int check_e = 4;
	InitList(L);
	for(int i=0,j=1; i<5 ;i++,j++){//假设表中原有5个数据 
		ListInsert(L,j,i);
	}
	PrintList(L);
	
	printf("值为%d的元素在L中第%d个位置\n",check_e,LocateElem(L,check_e));
}

按值查找时间复杂度:最好O(1);最坏O(n);平均O(n) 

3.单链表

3.1单链表的定义

3.1.1定义与重命名

struct LNode{ //定义单链表中的单个节点类型 
	ElemType data;       //数据域 每个节点存放一个数据元素 
	struct LNode *next;  //指针域 指向单链表中下一个节点 
}; 

若要增加一个节点则用malloc实现:

struct LNode *p = (struct LNode *)malloc(sizeof(struct LNode));//默认乘 1

重命名 

为了提升代码的可读性,在之后增加节点时可以用别名来写

typedef 该关键字 用于重命名数据类型 语法为:typedef <数据类型名> <别名>

eg:typedef <int> <zhengshu> 把int型重命名为“整数”类型(hhh为了提升代码可读性,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值