c语言进阶——数据结构——线性表

性表是一种常见的数据结构,它是一种有序的数据元素的集合,其中每个元素都有唯一的前驱和后继。

线性表有两种实现方式:顺序存储和链式存储。

顺序存储是将线性表的元素按顺序依次存放在一块连续的内存空间中。通过数组来实现线性表,可以通过下标直接访问和操作元素,查找元素的时间复杂度为O(1)。但是插入和删除元素需要平移其他元素,时间复杂度为O(n)。

链式存储是通过节点和指针的方式来实现线性表。每个节点存储数据元素以及指向下一个节点的指针。插入和删除元素只需修改指针,时间复杂度为O(1),但是查找元素需要遍历链表,时间复杂度为O(n)。

线性表常见的操作包括:

  • 插入:在指定位置插入一个元素,要求保持元素的顺序。
  • 删除:删除指定位置的元素,要求保持元素的顺序。
  • 查找:根据元素的值或者位置,找到对应的元素。
  • 修改:修改指定位置的元素的值。
  • 遍历:依次访问线性表中的每个元素。

线性表的应用非常广泛,例如数组、链表、栈和队列等数据结构都可以看做是线性表的具体实现。它们在算法和程序设计中扮演着重要角色,帮助我们解决各种实际问题。

代码实现步骤:

  1. 定义头文件和常量:包括引入标准输入输出头文件<stdio.h>和标准库头文件<stdlib.h>,以及定义宏常量OKERROROVERFLOWList_SizeListIncrement

  2. 定义数据类型和结构体:定义了线性表的元素类型ElemType和线性表的结构体类型SqList,其中包括了存放线性表的数组基地址elem、线性表的当前长度length和线性表当前分配的存储容量listsize

  3. 初始化线性表:InitList(SqList &L)函数用来初始化线性表,分配存储空间并设置长度和容量。

  4. 创建线性表:CreateList(SqList &L, int n)函数用来创建顺序表,将输入的元素存放到线性表中。

  5. 销毁线性表:Deatroy(SqList &L)函数用来销毁顺序表,即释放线性表的存储空间。

  6. 插入元素:ListInsert(SqList &L, int i, ElemType x)函数用来在指定位置插入元素。

  7. 删除元素:ListDelete(SqList &L, int i)函数用来删除指定位置的元素。

  8. 查找元素:LocateElem(SqList L, ElemType x)函数用来查找指定元素在线性表中的位置。

  9. 输出线性表:DispList(SqList L)函数用来输出线性表的所有元素。

  10. 逆置线性表:Contrary_sq(SqList La, SqList &Lb)函数用来将给定线性表逆置。

  11. 有序插入:Insert_Ordersq(SqList &La, ElemType x)函数用来在有序表中插入元素,保持有序性。

  12. 两个有序线性表归并:mergelist_sq(SqList La, SqList Lb, SqList &Lc)函数用来将两个有序的线性表归并成一个有序的线性表。

  13. 主函数:main()函数中包含了对上述函数的使用示例

 

功能块1:头文件和宏定义

#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define List_Size 100  //线性表存储空间的初始化配量
#define ListIncrement 10  //线性表存储空间的分配增量

这部分代码是引入头文件和定义宏常量的部分。stdio.h 头文件用于输入输出操作,stdlib.h 头文件用于动态内存分配。定义了一些常量,如 OK 表示成功,ERROR 表示错误,OVERFLOW 表示溢出,List_Size 表示线性表的初始大小,ListIncrement 表示线性表的存储空间分配增量。

功能块2:数据类型和结构体定义

typedef int ElemType;
typedef struct{
    ElemType *elem;//存放线性表的数组基地址
    int length;//线性表的当前长度
    int listsize;//线性表当前分配的存储容量
}SqList;

这部分代码定义了线性表元素类型 ElemType 为整型,并定义了线性表的结构体类型 SqList,包含了一个指向线性表元素的指针 elem,线性表的当前长度 length 和线性表的当前存储容量 listsize

功能块3:线性表的初始化

int InitList(SqList &L){
    L.elem=new ElemType[List_Size];
    if(!L.elem)exit(OVERFLOW);
    L.length=0;
    L.listsize=List_Size;
    return OK; 
}

这部分代码定义了初始化线性表的函数 InitList,该函数接收一个线性表 L 的引用作为参数。函数中首先动态分配了一个大小为 List_Size 的数组作为线性表的存储空间,并将 L.elem 指向该数组的基地址。然后将线性表的长度置为0,存储容量置为 List_Size。如果动态内存分配失败,则会出现溢出错误。最后返回状态值 OK

功能块4:创建线性表

void CreateList(SqList &L, int n){
    int i;
    for(i=0;i<n;i++){
        scanf("%d",&L.elem[i]);
        L.length++;
    }
}

这部分代码定义了创建线性表的函数 CreateList,该函数接收一个线性表 L 的引用和一个整数 n 作为参数。函数通过循环将用户输入的元素存放到线性表的数组中,并逐个增加线性表的长度。

功能块5:销毁线性表

void Deatroy(SqList &L){
    delete L.elem;
}

这部分代码定义了销毁线性表的函数 Deatroy,该函数接收一个线性表 L 的引用作为参数。函数使用 delete 关键字释放线性表的存储空间,防止内存泄漏。

功能块6:插入元素

int ListInsert(SqList &L, int i, ElemType x){
    int j;
    if(i<1 || i>L.length+1) return ERROR;
    if(L.length>=L.listsize){
        ElemType *newbase;
        newbase=(ElemType*)realloc(L.elem,(L.listsize+ListIncrement)*sizeof(ElemType));
        if(!newbase) exit(OVERFLOW);
        L.elem=newbase;
        L.listsize+=ListIncrement;
    }
    for(j=L.length-1;j>=i-1;j--){
        L.elem[j+1]=L.elem[j];
    }
    L.elem[i-1]=x;
    L.length++;
    return OK;
}

这部分代码定义了插入元素的函数 ListInsert,该函数接收线性表 L 的引用,一个整数 i 表示插入的位置,以及一个元素 x。首先判断插入位置是否合法,如果位置小于1或大于当前长度加1,则返回错误状态。如果线性表的长度超过存储容量,则会进行存储空间的扩展,每次扩展 ListIncrement 个元素大小。然后将插入位置之后的元素依次后移一个位置,腾出插入位置。最后将元素 x 插入到指定位置,线性表的长度增加,并返回状态值。

功能块7:删除元素

int ListDelete(SqList &L, int i){
    int j;
    if(i<1 || i>L.length) return ERROR;
    for(j=i;j<L.length;j++){
        L.elem[j-1]=L.elem[j];
    }
    L.length--;
    return OK;
}

这部分代码定义了删除元素的函数 ListDelete,该函数接收线性表 L 的引用和一个整数 i 表示要删除的位置。首先判断删除位置是否合法,如果位置小于1或大于当前长度,则返回错误状态。然后将删除位置之后的元素依次前移一个位置,覆盖要删除的元素。最后线性表的长度减一,并返回状态值。

功能块8:查找元素

int LocateElem(SqList L, ElemType x){
    int i;
    for(i=0;i<L.length;i++){
        if(L.elem[i]==x) return i+1;
    }
    return 0;
}

这部分代码定义了查找元素的函数 LocateElem,该函数接收一个线性表 L 的值传递和一个元素 x。函数通过遍历线性表的元素,逐个与目标元素进行比较,如果找到相等的元素,就返回该元素在线性表中的位置。如果找不到,则返回0。

功能块9:输出线性表

void DispList(SqList L){
    int i;
    if(L.length==0){
        printf("线性表为空!\n");
        return;
    }
    printf("线性表的元素为:");
    for(i=0;i<L.length;i++){
        printf("%d ",L.elem[i]);
    }
    printf("\n");
}

这部分代码定义了输出线性表的函数 DispList,该函数接收一个线性表 L 的值传递。函数首先判断线性表的长度是否为0,如果为空则输出相应的提示信息。然后遍历线性表的元素,并逐个输出到控制台。

功能块10:主函数

int main(){
    SqList L;
    int i, n, x;
    InitList(L);
    printf("请输入线性表的长度:");
    scanf("%d",&n);
    printf("请依次输入线性表的元素:");
    CreateList(L, n);

    printf("插入元素测试,请输入要插入的元素和位置(用空格分隔):");
    scanf("%d%d", &x, &i);
    if(ListInsert(L, i, x)==ERROR){
        printf("插入失败!\n");
    }else{
        printf("插入成功!\n");
    }

    printf("删除元素测试,请输入要删除的元素的位置:");
    scanf("%d", &i);
    if(ListDelete(L, i)==ERROR){
        printf("删除失败!\n");
    }else{
        printf("删除成功!\n");
    }

    printf("查找元素测试,请输入要查找的元素:");
    scanf("%d", &x);
    i=LocateElem(L, x);
    if(i==0){
        printf("未找到该元素!\n");
    }else{
        printf("元素 %d 在线性表中的位置是 %d\n",x, i);
    }

    DispList(L);

    Deatroy(L);

    return 0;
}

这部分代码是主函数,对上述定义的函数进行了测试和调用。首先初始化线性表 L,然后用户输入线性表的长度和元素,创建线性表。接下来进行插入元素、删除元素和查找元素的测试,并输出结果。最后输出线性表的所有元素,销毁线性表的存储空间,并正常结束程序。

以下是完整代码:

#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define List_Size 100  //线性表存储空间的初始化配量
#define ListIncrement 10  //线性表存储空间的分配增量
typedef int ElemType;
typedef struct{
	ElemType *elem;//存放线性表的数组基地址
	int length;//线性表的当前长度
	int listsize;//线性表当前分配的存储容量
}SqList;

int InitList(SqList &L){
  L.elem=new ElemType[List_Size];
  if(!L.elem)exit(OVERFLOW);
  L.length=0;
  L.listsize=List_Size;
  return OK; 
}
void CreateList(SqList &L,int n){//创建顺序表
	int i;
	for(i=0;i<n;i++){
		scanf("%d",&L.elem[i]);
		L.length++;
	}
}
void Deatroy(SqList &L){//销毁顺序表
	delete L.elem;
}

int ListInsert(SqList &L,int i,ElemType x){
	int j;
	ElemType *p;
	if(i<1||i>L.length)return ERROR;//插入位置不合法
	if(L.length>=L.listsize){//当前存储空间已满,增加分配
		p=(ElemType *)realloc(L.elem,(L.listsize+ListIncrement)*sizeof(ElemType));
		if(!p)exit(OVERFLOW);
		L.elem=p;
		L.listsize=L.listsize+ListIncrement;
	}
	for(j=L.length-1;j>=i;j--)L.elem[j+1]=L.elem[j];//插入位置之后的元素依次后移
	L.elem[i]=x;//插入元素
	++L.length;//表长增1
	return OK;
}
int ListDelete(SqList &L,int i){
	int j;
	if(i<1||i>L.length)return ERROR;//删除位置不合法
	for(j=i-1;j<L.length-1;j++)L.elem[j]=L.elem[j+1];//删除位置之后的元素依次前移
	--L.length;//表长增1
	return OK;
}
int LocateElem(SqList L,ElemType x){
	int i=1;
	while(i<=L.length&&L.elem[i-1]!=x)i++;
	if(i<=L.length)return i;
	else return ERROR;
}
void DispList(SqList L){//输出顺序表
	int i;
	for(i=0;i<L.length;i++)
	printf("%d ",L.elem[i]);
	printf("\n");
}

void Contrary_sq(SqList La,SqList &Lb){//将顺序表逆置
	int i;
	InitList(Lb);
	Lb.listsize=Lb.length=La.length;
	for(i=0;i<La.length;i++)Lb.elem[i]=La.elem[La.length-1-i];
}
int Insert_Ordersq(SqList &La,ElemType x){
	int i;
    ElemType *p;
	if(La.length>=La.listsize){//当前存储空间已满,增加分配
		p=(ElemType *)realloc(La.elem,(La.listsize+ListIncrement)*sizeof(ElemType));
		if(!p)exit(OVERFLOW);
		La.elem=p;
		La.listsize=La.listsize+ListIncrement;
	}
	for(i=La.length-1;x<La.elem[i]&&i>=0;i--)La.elem[i+1]=La.elem[i];
	La.elem[i+1]=x;//插入元素x
	++La.length;
	return OK;
}
void mergelist_sq(SqList La,SqList Lb,SqList &Lc){//两个有序表的归并
	int i,j,k;
	InitList(Lc);
	if(!Lc.elem)exit(OVERFLOW);
	i=0;j=0;k=0;
	while(i<La.length&&j<Lb.length){
		if(La.elem[i]<=Lb.elem[j]) Lc.elem[k++]=La.elem[i++];
		else Lc.elem[k++]=Lb.elem[j++];
	}
	while(i<La.length)Lc.elem[k++]=La.elem[i++];//将La中剩余元素插入到Lc中
	while(j<Lb.length)Lc.elem[k++]=Lb.elem[j++];//将Lb中剩余元素插入到Lc中
	Lc.length=La.length+Lb.length;
}

int main(){
	SqList L,La,Lb,Lc;
	int i=4;
	ElemType x=100;    	
	InitList(L);   //建空表
	CreateList(L,5);   //创建表
	ListInsert(L,i,x);
	DispList(L);

	ListDelete(L,i);
	DispList(L);

	printf("%d\n",LocateElem(L,x));

	Contrary_sq(L,Lb);
	DispList(Lb);

	InitList(La);
	CreateList(La,5);
	x=4;
	Insert_Ordersq(La,x);
	DispList(La);

	InitList(La);
	CreateList(La,5);
	DispList(La);

	InitList(Lb);
	CreateList(Lb,3);
	DispList(Lb);

	mergelist_sq(La,Lb,Lc);
	DispList(Lc);
	
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张謹礧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值