文章目录
前言
在生产中,为了方便管理数据,我们经常会需要将一些数据连续的存储起来。例如手机的通讯录中需要存储联系人的信息;图书管理系统中需要存储图书的信息等。
想到存储一系列相同类型的数据,我们就不免想到数组。数组可以实现将一些相同类型的数据存储到一块连续的空间中。其实,我们在这篇文章中要介绍的顺序表中的数据就是以数组的形式存储。
一、顺序表的定义
1、顺序表概念
顺序表是在计算机内存中以数组的形式保存的线性表,线性表的的顺序存储是指用一组地址连续的存储单元一次存储线性表中的各个元素,使得线性表中的逻辑结构上相邻的元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系,采用顺序存储结果的线性表通常称为线性表。顺序表是一种常见的数据结构,被广泛应用于各种应用程序和算法中,如排序、查找、数据处理等。
2、顺序表分类
1.静态顺序表:适应定长数组存储。
2.动态顺序表:使用动态开辟的数组存储。
二、顺序表的特点
顺序表具有以下特点:
元素之间的逻辑关系:在顺序表中,元素之间有一种逻辑顺序,即第一个元素位于索引0,第二个元素位于索引1,以此类推。这种顺序由数组的索引决定。
动态分配:顺序表的大小可以根据需要动态调整。当需要添加或删除元素时,可以通过调整数组的大小来实现。
随机访问:顺序表中的元素可以通过索引进行随机访问,即可以在任意位置读取或修改元素。
空间效率:顺序表的空间效率较高,因为元素可以直接存储在数组中,不需要额外的空间来。
三、顺序表的运算
数据结构顺序表是一种常见的数据结构,它使用数组来存储一系列元素。顺序表的主要运算包括插入、删除、输出、判空
1、插入运算
在顺序表中插入一个元素,需要找到插入位置并将该位置及其之后的元素向后移动一位,然后将新元素放在插入位置。如果需要插入的位置超过了顺序表的大小,则需要动态扩容数组。
代码实现:
/*插入元素*/
int insert(SeqList *L, int i, DataType x) {
int j;
/*判断是否满*/
if(full(L)) {
printf("Error[10001],顺序表已满!\n");
return 10001;
}
/*判断位置i合法性*/
if(i<1 || i>length(L)+1) {
printf("Error[10002],位置i不合法!\n");
return 10002;
}
/*移动元素,向后移动*/
for(j=L->length; j>=i; j--) {
L->data[j] = L->data[j-1];
}
L->data[j] = x;
L->length++;
return 0; /*ok!*/
}
2、删除运算
从顺序表中删除一个元素,需要找到该元素的位置并将该位置及其之后的元素向前移动一位。如果删除的位置是顺序表的最后一个元素,则需要将数组的大小减一。
代码实现:
/*删除元素*/
int delete(SeqList *L, int i, DataType *x) {
int j;
//判断输入元素的位置是否合法
if(i<1 || i>length(L)+1) {
printf("Error[10002],位置i不合法!\n");
return 10002;
}
x=L->data[i] ;
for(j=i; j<L->length-1; j++)
L->data[j]=L->data[j+1];
L->length--;
return 0;//删除完成
}
3、输出循序表
使用循环遍历数组并逐个输出元素:可以使用for循环或while循环遍历数组,逐个访问元素并输出它们的值。
代码实现:
/*输出顺序表*/
void print(SeqList *L) {
int i;
if(empty(L)) {
printf("顺序表为空!");
return ;
}
printf("顺序表为:");
for(i=0; i<L->length; i++) {
printf("%d ", L->data[i]);
}
printf("\n");
}
4、判空运算
判断顺序表的长度是否为0:如果顺序表的的长度为0,则该顺序表为空。
代码实现:
/*是否空*/
int empty(SeqList *L) {
return (L->length == 0)?1:0;
}
四、顺序表和链表的比较
顺序表和链表是两种常见的数据结构,它们各有优缺点,下面进行比较:
1、存储方式
顺序表:顺序表是采用连续的存储空间来存储数据元素,每个元素都有一个固定的位置,因此可以通过下标直接访问元素。
链表:链表则是通过非连续的存储空间来存储数据元素,每个元素都有一个指针指向下一个元素,因此需要通过指针访问元素。
2、插入和删除操作
顺序表:顺序表的插入和删除操作需要移动元素,因此效率较低。当插入或删除元素时,可能需要移动大量元素以保持连续性。时间复杂度为O(n)。
链表:链表的插入和删除操作只需要修改指针指向,因此效率较高。当插入或删除元素时,只需要修改指针即可。时间复杂度为O(1)。
3、内存的利用程度
顺序表:顺序表的长度是固定的,因此在存储元素的个数超过预分配的空间时,需要重新分配内存空间。这增加了额外的开销。
链表:链表的长度可以动态增长,因此对内存的利用程度较高。当需要添加或删除元素时,不需要重新分配内存空间。
4、顺序性
顺序表:顺序表支持随机存取,可以通过下标直接访问元素。
链表:链表不支持随机存取,只能从表头按顺序存取元素。在某些情况下,访问元素可能需要遍历整个链表。
综上所述,顺序表和链表各有其优缺点,需要根据具体的应用场景来选择合适的数据结构。
五、完整代码
1、代码实现
#include <stdio.h>
#include "SeqList.h"
//#include "welcome.h"
int main(int argc, char* argv[])
{
SeqList L;
int cmd;
int i;
int m,n;
DataType x;
//
// for(i=0;i<strlen(welcome);i++)
// {
// printf("%c",welcome[i]);
// for(m=0;m<10000;m++)
// for(n=0;n<1000;n++)
// {
// ;
// }
// }
printf("\n\n\n");
printf("-----------顺序表演示程序----------\n");
do
{
printf("1. 初始化顺序表\n");
printf("2. 插入元素\n");
printf("3. 删除元素\n");
printf("4. 判断顺序表是否为空\n");
printf("5. 判断顺序表是否满\n");
printf("6. 输出顺序表\n");
printf("10. 帮助\n");
printf("0. 退出\n");
printf("请输入您要进行的操作(1~6,0退出):");
scanf("%d", &cmd);
switch(cmd)
{
case 1://初始化顺序表
if(!init(&L))
{
printf("顺序表已初始化!\n");
}
break;
case 2://插入元素
printf("请输入位置i,插入元素x(i,x):");
scanf("%d,%d",&i,&x);
if(!insert(&L,i,x))
{
printf("元素(%d) 已插入位置[%d]\n",x, i);
}
break;
case 3: //删除元素
printf("请输入删除元素位置:");
scanf("%d,%d",&i,&x);
if(!delete(&L,i,&x))
{
printf("元素已删除!\n");
}
else{
printf("元素删除失败!\n") ;
}
break;
case 4: //判断顺序表是否为空
{
if(empty(&L)){
printf("顺序表为空!\n");
}else{
printf("顺序表不为空!\n");
}
}break;
case 5://判断顺序表是否满
if(full(&L))
{
printf("顺序表已满!\n");
}
else
{
printf("顺序表未满!\n");
}
case 6://输出顺序表
print(&L);
break;
case 10://帮助
printf(" 本程序为顺序表的演示程序,有XXX设计开发,程序完成了。。。。功能!。。。\n");
break;
}
}while(cmd != 0);
return 0;
}
/*
SeqList.c 顺序表实现
*/
#include "SeqList.h"
/*顺序表初始化*/
int init(SeqList *L) {
L->length = 0;
return 0;
}
/*顺序表的长度*/
int length(SeqList *L) {
return L->length;
}
/*顺序表是否满*/
int full(SeqList *L) {
return (L->length == MAXSIZE)?1:0;
}
/*是否空*/
int empty(SeqList *L) {
return (L->length == 0)?1:0;
}
/*插入元素*/
int insert(SeqList *L, int i, DataType x) {
int j;
/*判断是否满*/
if(full(L)) {
printf("Error[10001],顺序表已满!\n");
return 10001;
}
/*判断位置i合法性*/
if(i<1 || i>length(L)+1) {
printf("Error[10002],位置i不合法!\n");
return 10002;
}
/*移动元素,向后移动*/
for(j=L->length; j>=i; j--) {
L->data[j] = L->data[j-1];
}
L->data[j] = x;
L->length++;
return 0; /*ok!*/
}
/*删除元素*/
int delete(SeqList *L, int i, DataType *x) {
int j;
//判断输入元素的位置是否合法
if(i<1 || i>length(L)+1) {
printf("Error[10002],位置i不合法!\n");
return 10002;
}
x=L->data[i] ;
for(j=i; j<L->length-1; j++)
L->data[j]=L->data[j+1];
L->length--;
return 0;//删除完成
}
/*输出顺序表*/
void print(SeqList *L) {
int i;
if(empty(L)) {
printf("顺序表为空!");
return ;
}
printf("顺序表为:");
for(i=0; i<L->length; i++) {
printf("%d ", L->data[i]);
}
printf("\n");
}
2、运行结果
总结
以上就是我对顺序表的总结,本文仅仅简单介绍了顺序表的概念、特点、运算以及顺序表和链表的优缺点比较。
顺序表,或称为顺序向量、一维数组,是线性表的一种特殊表现形式。它以数组的形式存储数据,每个元素在内存中按顺序依次存放。顺序表的主要特点包括:
- 元素之间的逻辑关系:顺序表中的元素之间没有直接的逻辑关系,即它们在内存中的位置没有必然联系。
- 插入和删除操作:在顺序表中,插入和删除操作需要移动元素来保持顺序。例如,在顺序表的开头插入一个元素,需要将所有后续元素向后移动一位;删除一个元素也是如此,需要将后续元素向前移动一位。
- 查找操作:顺序表的查找操作通常是线性的,即从表的一端开始,按顺序逐个检查每个元素直到找到所需的元素或到达表的另一端。
- 存储空间:顺序表需要连续的存储空间,因此可能会因为存储空间的限制而无法存储大量的数据。
- 随机访问:由于顺序表中的元素是按顺序存储的,因此可以通过索引直接访问任意位置的元素,这是顺序表的一个优点。
这些特点使得顺序表在某些情况下具有优势,例如需要频繁查找操作的数据集,因为查找操作的时间复杂度为O(1),即常数时间复杂度。然而,对于需要频繁插入和删除操作的场景,顺序表可能不是最佳的选择,因为这些操作的时间复杂度为O(n),其中n是顺序表的长度。在这种情况下,使用链表等其他数据结构可能更为合适。