【C语言】详解顺序表

顺序表的定义:顺序表是在计算机内存中以数组的形式保存的线性表,线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素、使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系,采用顺序存储结构的线性表通常称为顺序表。顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存储单元中。

顺序表的优点:

  • 存取效率高,无需为表示表中元素之间的逻辑关系而增加额外的存储空间。
  • 可以快速地存取表中任一位置的元素。

顺序表的缺点:

  • 插入和删除操作不方便:在顺序表中插入或删除元素时,通常需要移动大量的元素以保持连续性,这会导致效率较低。特别是在表的中间插入或删除元素时,时间复杂度可能达到O(N),其中N是表的长度。尽管在表的尾部插入或删除元素的效率较高(时间复杂度为O(1)),但在其他位置的操作效率较低。
  • 长度固定:顺序表的大小是固定的,这在一定程度上限制了其灵活性。当需要存储更多的元素时,必须重新分配更大的内存空间,这可能导致时间和资源的浪费。另一方面,当存储的元素较少时,分配的内存空间可能得不到充分利用,这也造成了资源的浪费。
  • 空间利用率低:由于顺序表要求内存空间连续,因此在某些情况下可能会导致内存空间的浪费。例如,当表中有大量删除操作时,表中可能会产生很多空闲的空间,但这些空间无法被其他数据结构利用。
  • 无法充分利用缓存:顺序表在内存中的连续性可能会导致缓存利用率降低。在现代计算机系统中,CPU通常使用缓存来提高访问内存的速度。由于顺序表的元素在内存中是连续存储的,因此可能会导致缓存中出现很多未使用的空间,从而降低了缓存的利用率。

顺序表主要运算特点:

  • 随机访问:由于顺序表在内存中以连续的方式存储数据元素,因此可以在O(1)时间内通过下标直接访问表中的任何一个元素。这种随机访问的特性使得顺序表在很多场景下非常高效,例如在查找特定元素或修改特定元素的值时。
  • 插入和删除操作不方便:在顺序表中插入或删除元素时,通常需要移动大量的元素以保持连续性,这会导致效率较低。特别是在表的中间插入或删除元素时,时间复杂度可能达到O(N),其中N是表的长度。尽管在表的尾部插入或删除元素的效率较高(时间复杂度为O(1)),但在其他位置的操作效率较低。
  • 存储密度高:顺序表在内存中的存储是连续的,因此每个元素只需要存储数据本身,不需要额外的空间来存储指针等信息。相比之下,链式存储结构中的每个节点除了存储数据元素外,还需要额外的空间来存储指针,因此顺序表的存储密度较高。
  • 拓展容量不方便:顺序表的大小是固定的,这在一定程度上限制了其灵活性。当需要存储更多的元素时,必须重新分配更大的内存空间,这可能导致时间和资源的浪费。另一方面,当存储的元素较少时,分配的内存空间可能得不到充分利用,这也造成了资源的浪费。

综上所述,顺序表的运算特点主要包括随机访问插入删除操作不方便存储密度高以及拓展容量不方便等。在实际应用中,需要根据具体的需求和场景来选择合适的数据结构。

 1.定义顺序表的最大长度

#define MAX_SIZE 300

2.定义顺序表结构体

  typedef struct {  
    int data[MAX_SIZE];  // 存储数据元素  
    int length;          // 当前存储数据的个数  
} SqList;                  //别名

3.初始化顺序表 

void InitList(SqList *L) {  
    L->length = 0;  
}  

4.顺序表的常用操作的实现 

4.1判断顺序表是否为空

int IsEmpty(SqList L) {  
    return L.length == 0;  
}

4.2判断顺序表是否已满

int IsFull(SqList L) {  
    return L.length == MAX_SIZE;  
} 

4.3在顺序表末尾插入元素

void InsertList(SqList *L, int x) {  
    if (IsFull(*L)) {  
        printf("Error: List is full\n");  
        return;  
    }  
    L->data[L->length++] = x;  
} 

5.对顺序表进行增删改查操作 

5.1.插入元素

线性表的插入是指在表的第i个位置上(因为C语言的下标是从0开始的,所以插入位置下标为i-1)插入一个值为x的元素,插入后使原表长增加1,称为表长度为n+1的表。

要注意一下几点问题:

1.首先要检查顺序表是否已满,在表满的情况下不能插入,否则会产生溢出错误

2.检查插入位置的有效性,插入的有效范围是1<=i<=n+1(n是原来的表长)

3.注意数据移动的方向,必须从原线性表的最后一个结点开始往后移动

int InsertList(SqList *L, int index, int value) {  
    if (index < 1 || index > L->length + 1 || L->length >= MAX_SIZE) {  
        return 0; // 插入位置不合法或表已满,返回0表示插入失败  
    }  
    for (int i = L->length; i >= index; i--) {  
        L->data[i] = L->data[i - 1]; // 将index位置及其之后的元素向后移动一位  
    }  
    L->data[index - 1] = value; // 在index位置插入新元素  
    L->length++; // 表长加1  
    return 1; // 返回1表示插入成功  
}

5.2.删除元素

线性表的删除操作是指将第i个元素(C语言数组下标从0开始,删除位置下标为i-1)从顺序表中去掉,删除后顺序表长度-1

顺序表删除结点的步骤如下

1.将要删除的元素赋值给指针x所指的变量

2.将第i+1到最后一个结点依次顺序向前移动

3.顺序表长度-1,删除成功,并返回

int InsertList(SqList *L, int index) {  
    if (index < 1 || index > L->length) {  
        return 0; // 删除位置不合法,返回0表示删除失败  
    }  
    for (int i = index; i < L->length; i++) {  
        L->data[i - 1] = L->data[i]; // 将index位置及其之后的元素向前移动一位  
    }  
    L->length--; // 表长减1  
    return 1; // 返回1表示删除成功  
}

5.3.查找元素

1.按位置查找

按位置查找就是查找第i个位置的元素的值,在i无效时返回出错,有效时返回成功,并用指针x所指的变量传回第i个元素的值 代码如下:

int GetElem(SeqList* L, int i, DataType* x)
{
	if (i<1 || i>L->Length)
	{
		return 0;
	}
	else
	{
		*x = L->data[i - 1];
		return 1;
	}
}

注意:在查找的时候要先判断i是不是合法的(是否为负数是否超过数组的最大下标值等),以及要考虑到i不是合法的数据时,要怎么处理。 

2.按值查找操作

按值查找是指在顺序表中,查找与给指定值x相等的数据元素所在位置的下标。

int Locate(SeqList* L, DataType x)
{
	int i = 0;
	while (i < L->Length && L->data[i] != x)
	{
		i++;
	}
	if (i > L->Length)
	{
		return 0;
	}
	else
	{
		return i + 1;
	}
}

6.输出表中的元素

输出顺序表的元素,就是遍历一次一维数组,然后把它打印出来 

void DispList(SeqList* L)
{
    int i = 0;
    for (i = 0; i < L->Length; i++)
    {
        printf("%d ", L->data[i]);
    }

顺序表的操作的完整程序代码

#include <stdio.h>
#include <stdlib.h>
#include<cstring>
// 定义顺序表的最大长度  
#define MAX_SIZE 100  
  
// 定义顺序表结构体  
typedef struct {  
    int data[MAX_SIZE];  // 存储数据元素  
    int length;          // 当前存储数据的个数  
} SqList;  
  
// 初始化顺序表  
void InitList(SqList *L) {  
    L->length = 0;  
}  
  
// 判断顺序表是否为空  
int IsEmpty(SqList L) {  
    return L.length == 0;  
}  
  
// 判断顺序表是否已满  
int IsFull(SqList L) {  
    return L.length == MAX_SIZE;  
}  
  
// 在顺序表插入元素  
int InsertList(SqList *L, int index, int value) {  
    if (index < 1 || index > L->length + 1 || L->length >= MAX_SIZE) {  
        return 0; // 插入位置不合法或表已满,返回0表示插入失败  
    }  
    for (int i = L->length; i >= index; i--) {  
        L->data[i] = L->data[i - 1]; // 将index位置及其之后的元素向后移动一位  
    }  
    L->data[index - 1] = value; // 在index位置插入新元素  
    L->length++; // 表长加1  
    return 1; // 返回1表示插入成功  
}  

// 在顺序表的第pos个元素之前插入元素x  
void InsertListPos(SqList *L, int pos, int x) {  
    if (L->length >= MAX_SIZE) {  
        printf("Error: List is full\n");  
        return;  
    }  
    if (pos < 0 || pos > L->length) {  
        printf("Error: Invalid position\n");  
        return;  
    }  
    int i =0 ;
    for (i = L->length; i > pos; i--) {  
        L->data[i] = L->data[i-1];  
    }  
    L->data[pos] = x;  
    L->length++;  
}

// 从顺序表中删除指定元素x  
int DeleteListElement(SqList *L, int x) {  
    int i;  
    for (i = 0; i < L->length; i++) {  
        if (L->data[i] == x) {  
            break;  
        }  
    }  
    if (i == L->length) {  
        printf("Error: Element not found\n");  
        return -1;  
    }  
    int j = i; 
    for (j = i; j < L->length - 1; j++) {  
        L->data[j] = L->data[j+1];  
    }  
    L->length--;  
    return 0;  
}
  
// 在顺序表的第pos个元素之前插入元素x  
void UpdateListElement(SqList *L, int pos, int new_val) {  
    if (pos < 0 || pos >= L->length) {  
        printf("Error: Invalid position\n");  
        return;  
    }  
    L->data[pos] = new_val;  
}

// 在顺序表中查找指定元素x的位置  
int SearchListElement(SqList L, int x) {  
	int i = 0;
    for ( i = 0; i < L.length; i++) {  
        if (L.data[i] == x) {  
            return i;  
        }  
    }  
    return -1;  
}
  
// 打印顺序表中的元素  
void PrintList(SqList L) {  
    int i;  
    for (i = 0; i < L.length; i++) {  
        printf("%d ", L.data[i]);  
    }  
    printf("\n");  
}
// 打印顺序表中的元素
void PrintList(SeqList L) {
    int i;
    for (i = 0; i < L.length; i++) {
        printf("%d ", L.data[i]);
    }
    printf("\n");
}
int main(int argc, char *argv[]) {
	char welcome[] = "\
           /\ \
          ( *)======/\==== \
           )(      /  \ \
__________/  )    /    \ \
\___         /   / \"\"   \ \
  \____    _/   / (**)   \ \
     / \__/    (----------) \
    /____|__//_ ( name- ) \
         |      ( wjj ) \
         |       (      )\
         |        (____)\
        _|__\
         \\    ☆新年 . 快乐☆";
	int i = 0;
	int m = 0;
	int n = 0;
    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");
 
	int number;
    SeqList L;
    int x;  //元素x
    int pos; //第pos元素
    int new_val; //新的数组
    do {
    	printf("-----------顺序表演示程序----------\n");
        printf("1. 初始化顺序表\n");
        printf("2. 往顺序表尾部插入元素\n");
        printf("3. 插入数据\n");
        printf("4. 删除元素\n");
        printf("5. 更新元素\n");
        printf("6. 查询指定元素的位置\n");
        printf("7. 判断顺序表是否为空\n");
        printf("8. 判断顺序表是否满\n");
        printf("9. 打印顺序表中的元素\n");
        printf("10. 帮助\n");
        printf("0. 退出\n");
        printf("请输入您要进行的操作(1~10,0退出):");
        scanf("%d", &number);
        switch (number) {
            case 1:
                InitList(&L);
                printf("初始化成功!\n1");
                break;
            case 2:
                //往顺序表尾部插入元素
                printf("请输入需要往顺序表尾部插入元素x\n");
                scanf("%d",&x);
                InsertList(&L,x);
                printf("元素%d已插入顺序表末尾",x);
                printf("新的顺序表为:\n");
				PrintList(L);
                break;
            case 3:
                printf("请输入需要插入的位置pos和元素x\n");
                scanf("%d %d",&pos,&x);
                InsertListPos(&L,pos,x);
                printf("元素(%d)已插入位置[%d]\n",x, pos);
                printf("新的顺序表为:\n");
				PrintList(L);
                break;
            case 4:
                printf("请输入需要删除的元素x\n");
                scanf("%d",&x);
                DeleteListElement(&L,x);
                printf("元素已删除\n",x);
                printf("新的顺序表为:\n");
				PrintList(L);
                break;
            case 5:
                printf("请输入需要更新的元素x,以及元素x更新的新值\n");
                scanf("%d %d",&x,&new_val);
                pos = SearchListElement(L,x); //查找元素x所在的位置
                UpdateListElement(&L,pos,new_val);
                printf("元素%d已更新为%d\n",x,new_val);
                printf("新的顺序表为:\n");
				PrintList(L);
                break;
            case 6:
                printf("请输入需要查询的元素x\n");
                scanf("%d",&x);
                pos = SearchListElement(L,x); //查找元素x所在的位置
                printf("元素%d所在的位置为%d\n",x,pos);
                break;
            case 7:
                if(IsEmpty(L))
                	printf("顺序表为空\n");
				else
					printf("顺序表不为空\n");
                break;
            case 8:
               	if(IsFull(L))
				   printf("请注意,顺序表已满!\n");
				else
					printf("顺序表未满!\n");
                break;
            case 9:
                PrintList(L);
                break;
            case 10:
            	InitList(&L);
			    printf("您好!请问有什么可以帮助您\n");
				break;
        }
    } while (number != 0); // 当输入0时退出循环
	return 0;
}

 

在季老师的指导下,让我收获了知识和成长。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值