欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

数据结构之顺序表的实现

程序员文章站 2022-03-10 12:28:12
数据结构之顺序表的实现 一、原理 1.定义 顺序表是在计算机中以数组形式保存的。 2.特点 在计算机中占用连续的一段内存 一旦声明,空间大小一般不变 二、初始化相关操作 包括: 1. 结构体的定义 2. 顺序表的创建 3. 顺序表清空 4. 判断顺序表是否为空 1.结构体定义 即定一个满足顺序表定义 ......

数据结构之顺序表的实现

一、原理

1.定义

顺序表是在计算机中以数组形式保存的。


2.特点

  • 在计算机中占用连续的一段内存

  • 一旦声明,空间大小一般不变


二、初始化相关操作

包括:

  1. 结构体的定义
  2. 顺序表的创建
  3. 顺序表清空
  4. 判断顺序表是否为空

1.结构体定义

即定一个满足顺序表定义的结构体,其中包含 数组、存储长度、总长度。

typedef int elemtype; //将int抽象为elemtype,表明顺序表也可以存储其他类型(如将int改为char)
struct list
{
	elemtype *list; 
	//声明数组用于给顺序表存储数据,等价于以下声明方式
	//elemtype[] list;
	int length; //用于记录顺序表存储的数据长度
	int maxsize; //用于记录顺序表最大长度(即最多存储数据)
}

2.初始化

对顺序表进行初始化,包括分配自定义长度的数组空间,设定存储长度为0,存储长度为规定值

//初始化,传入需要初始化的顺序表和初始化长度
void initlist(struct list *l,int maxsize){
  //初始化长度合法性判断
  if(maxsize<0){
    printf("初始化长度非法!\n");
    exit(1); //退出程序
  }
  //对顺序表长度进行赋值
  l->maxsize = maxsize;
  //根据初始化长度和存储数据类型来动态分配数组
  l->list = malloc(sizeof(maxsize*sizeof(elemtype)));
  //分配成功判定
  if(!l->list){
    printf("动态分配存储失败\n");
    exit(1);
  }
  //初始化存储数据为0个
  l->length = 0;
}

3.清空

将顺序表内容清空,用于某些题目要求或节省空间

//清空,传入需要清空的顺序表
void clearlist(struct list *l){
  //判断顺序表是否已经为空
  if(l->list!=null){
    free(l->list); //释放顺序表中数组内存
    l->list = 0; 
    l->length = 0;
    l->maxsize = 0;
  }
}

4. 判断是否为空

判断顺序表是否为空,在某些操作之前,先要判断顺序表是否为空,防止出错

int isempty(struct list *l){
  return l->length==0?1:0; //顺序表最大长度为0则为空返回1,否则返回0
}

三、增加相关操作

包括:

  1. 向表头插入元素x
  2. 向表尾插入元素x
  3. 向第n个位置插入元素x
  4. 向递增的线性表中插入元素x,之后仍然保持有序

进行操作之前,还需要一个方法,当插入元素超过数组长度时,将数组容量扩大,即重新申请空间

tip:将顺序表扩大一倍空间

void remalloc(struct list *l){
	elemtype *p = realloc(l->list,2*l->maxsize*sizeof(elemtype));
  if(!p){
    printf("空间分配失败\n");
    exit(1);
  }
  l->list = p; //使list重新指向新生成的空间
  l->maxsize = 2*l->maxsize;
  printf("存储空间已经扩大为2倍\n");
}	

1.向表头插入元素x

void insertelemtohead(struct list *l,elemtype x){
  int i;
  //判断存储空间是否已满
	if(l->length==l->maxsize){
    printf("存储空间已满,重新分配中...");
    remalloc(l);
  }
  //所有元素后移
  for(i=l->length;i>0;i--){
    l->list[i+1]=l->list[i];
  }
  l->list[i]=x;
  l->length++;
}

2.向表尾插入元素x

void insertelemtotail(struct list *l,elemtype x){
	 //判断存储空间是否已满
	if(l->length==l->maxsize){
    printf("存储空间已满,重新分配中...");
    remalloc(l);
  }
  l->list[l->length++]=x;
}

3.向线性表l的第n个位置插入元素x

void insertelemsomewhere(struct list *l,elemtype x,int n){
   //判断存储空间是否已满
   if(l->length==l->maxsize){
   printf("存储空间已满,重新分配中...");
   remalloc(l);
 }
 int i;
 for(i=l->length;i>=n;i--){
 	l->list[i] = l->list[i-1];
 }
 l->list[i] = x;
 l->length--;
}

四、删除相关操作

包括:

  1. 删除表头元素并返回被删除的值

  2. 删除第n个元素并返回被删除元素

  3. 从线性表l中删除值为x的第一个元素


1.删除表头元素并返回被删除的值

删除表头第一个元素,长度减少1,返回被删除的值

elemtype delheadelem(struct list *l){
	elemtype x = l->list[0];
	//合法性判断
	if(l->length==0){
		 printf("线性表为空,不能删除\n");
     exit(1);
	}
	for(int i=0;i<l->length;i++){
		l->list[i] = l->list[i+1];
	}
	l->length--;
	return x;
}

2.删除第n个元素并返回被删除元素

elemtype delsomeelem(struct list *l,int n){
  if(n<l->length){
    printf("n位置越界,不能删除");
    exit(1);
  }
  elemtype x = l->list[n-1];
  for(int i=n;i<l->length;i++){
    l->list[i]=l->list[i+1];
  }
  l->length--;
  retur x;
}

3.从线性表l中删除值为x的第一个元素

从线性表l中删除值为x的第一个元素,若删除成功则返回1,否则返回0

int delelemknown(struct list *l,elemtype x){
	int i,j;
  //先找出值为x的下标
  for(i=0;i<l->length;i++){
    if(l->list[i]==x){
      break;
    }
  }
  for(j=i;i<l->length;j++){
    l->list[j]=l->list[j+1];
  }
  l->length--;
  return 1;
}

五、修改相关操作

包括:

  1. 把线性表中第n个元素修改为x

1.把线性表中第n个元素修改为x

把线性表中第n个元素修改为x,若成功则返回1,失败返回0
int updateelemknown(struct list *l,elemtype x,int n){
	if(n>l->length||n<1){
    return 0;
  }
  l->list[n]=x;
  return 1;
}

六、查找相关操作

包括:

  1. 查找第n个位置的值

  2. 顺序遍历输出所有值

  3. 返回值等于x的下标


1.查找第n个位置的值

输入要查找的坐标,若合法则范围对应的值,若非法则提示并推出

int getelem(struct list *l,int n){
  if(n<0||n>l->maxsize){
    printf("查找位置超出长度!\n");
    exit(1);
  }
  return l->list[n-1]; //n-1的原因是查找的第n个是从1开始计数,而数组是从0开始计数
}

2.顺序遍历输出所有值

输出顺序表中的所有值

void getall(struct list *l){
	int i = 0;
	while(i<l->length){
		printf(l->list[i]+"\t");
		i++;
	}
	printf("\n");
}

3.查找值为x的节点并返回其坐标

输入要查找的值x,若存在则范围首次出现的下标,否则返回0

void findelem(struct list *l,elemtype x){
	int i;
	for(i=0;i<l->length;i++){
		if(l->list[i]==x){
			return i;
		}
	}
}

七、总结

1.优点

  • 查找方便
  • 空间利用率高

2.缺点

  • 删除和增加操作效率低
  • 空间固定,不易扩展

八、完整代码

#include "stdio.h"
#include <stdlib.h>
/**
 * =======顺序表的定义=========
 */
typedef int elemtype;
//结构体定义
struct list{
    elemtype *list;//存储数据
    int length;//存储长度
    int maxsize;//最大长度
};

//初始化
void initlist(struct list *l,int maxsize){
    //初始化长度合法性判断
    if(maxsize<0){
        printf("初始化长度非法!\n");
        exit(1); //退出程序
    }
    l->maxsize = maxsize;
    l->list = malloc(sizeof(maxsize* sizeof(elemtype)));
    //判断分配空间是否成功
    if(!l->list){
        printf("空间分配失败");
        exit(1);
    }
    l->length=0;
}

//清空
void clearlist(struct list *l){
    if(l->list!=null){
        free(l->list);
        l->list=0;
        l->maxsize=0;
        l->length=0;
    }
}

//判空
int isempty(struct list *l){
    return l->length==0?1:0;
}

/**
 * =======增加操作=========
 */

//空间再分配
void remalloc(struct list *l){
    elemtype *p = realloc(l->list,2*l->maxsize* sizeof(elemtype));
    if(!p){
        printf("空间分配失败");
        exit(1);
    }
    l->list = p;
    l->maxsize = 2*l->maxsize;
    printf("空间已扩大两倍");
}

//向表头插入元素
void insertelemtohead(struct list *l,elemtype x){
    if(l->length==l->maxsize){
        remalloc(l);
        printf("空间已满,重新分配中");
    }
    for(int i=l->length;i>0;i++){
        l->list[i-1] = l->list[i];
    }
    l->list[0] = x;
    l->length++;
}

//向表尾插入元素
void insertelemtotail(struct list *l,elemtype x){
    if(l->length==l->maxsize){
        remalloc(l);
        printf("空间已满,重新分配中");
    }
    l->list[l->length++] = x;
}

//向线性表l的第n个位置插入元素x
void insertelemsomewhere(struct list *l,elemtype x,int n){
    int i;
    if(l->length==l->maxsize){
        remalloc(l);
        printf("空间已满,重新分配中");
    }
    for(i=l->length;i>=n;i--){
        l->list[i]=l->list[i-1];
    }
    l->list[i]=x;
    l->length++;
}

/**
 * =======删除操作=========
 */

//删除表头元素并返回被删除的值
void delheadelem(struct list *l){
    elemtype x = l->list[0];
    if(l->length==0){
        printf("顺序表为空,删除失败!");
        exit(1);
    }
    for(int i=1;i<l->length;i++){
        l->list[i-1] = l->list[i];
    }
    l->length--;
}

//删除第n个元素并返回被删除元素
elemtype delsomeelem(struct list *l,int n){
    elemtype x = l->list[n-1];
    if(n>l->length){
        printf("n位置越界,不能删除");
        exit(1);
    }
    for(int i=n;i<l->length;i++){
        l->list[i-1] = l->list[i];
    }
    l->length--;
    return x;
}

//从线性表l中删除值为x的第一个元素
int delelemknown(struct list *l,elemtype x){
    int i,j;
    for(i=0;i<l->length;i++){
        if(l->list[i]==x){
            break;
        }
    }
    for(j=i;j<l->length;j++){
        l->list[j]=l->list[j+1];
    }
    l->length--;
    return 1;
}

/**
 * =======修改操作=========
 */
//把线性表中第n个元素修改为x
int updateelemknown(struct list *l,elemtype x,int n){
    if(n>l->length||n<1){
        return 0;
    }
    l->list[n]=x;
    return 1;
}

/**
 * =======查找操作=========
 */
 //查找第n个位置的值
 int getelem(struct list *l,int n){
     if(n<0||n>l->maxsize){
         printf("查找位置超出长度!\n");
         exit(1);
     }
     return l->list[n-1]; //n-1的原因是查找的第n个是从1开始计数,而数组是从0开始计数
 }

 //顺序遍历输出所有值
 void getall(struct list *l){
     int i = 0;
     while(i<l->length){
         printf("%d\t",l->list[i]);
         i++;
     }
     printf("\n");
 }
//查找值为x的节点并返回其坐标
int findelem(struct list *l,elemtype x){
    int i;
    for(i=0;i<l->length;i++){
        if(l->list[i]==x){
            return i;
        }
    }
}

//主函数
int main()
{
     //初始化操作测试
    struct list l;
    initlist(&l,20);
    //插入操作测试
    insertelemtohead(&l,2);
    insertelemsomewhere(&l,4,2);
    insertelemtotail(&l,5);
    printf("%d\n",l.list[0]);
    printf("%d\n",l.list[1]);
    //删除操作测试
    delelemknown(&l,2);
    printf("%d\n",l.list[0]);
    //修改操作测试
    updateelemknown(&l,8,1);
    //查找操作测试
    printf("%d\n",getelem(&l,2));
    printf("%d\n",findelem(&l,8));
    printf("%d\n",l.list[0]);
    getall(&l);
}