03 顺序表

目录

  1. 线性表
  2. 顺序表
  3. 练习

线性表(Linear list)是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串。。。

线性表在逻辑上时线性结构,是连续的一条直线。但在物理结构上不一定是连续的,存储时,通常以数组和链式结构的形式存储

在这里插入图片描述

2. 顺序表

2.1 概念和结构

顺序表是一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改

顺序表一般可以分为:

  1. 静态顺序表:使用定长数组存储元素
    在这里插入图片描述

  2. 使用动态开辟的数组

在这里插入图片描述

2.2 接口实现

静态顺序表只适用于确定知道存多少数据的场景.静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用.所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表

头文件

#pragma once
#include <stdio.h>
顺序表的静态存储
//#define N 7
//typedef int SLDataType;
//
//typedef struct _SeqList
//{
//	SLDataType array[N];   //定长数组
//	size_t size;           //有效数据的个数
//}SeqList;

//顺序表的动态存储
typedef int SLDataType;

typedef struct _SeqList
{
	SLDataType *array;   //动态开辟的数组
	size_t size;           //有效数据的个数
	size_t capacity;      //容量大小
}SeqList;

//接口
//初始化
void SLInit(SeqList* psl);

//增加
//头插
void SLPushFront(SeqList* psl, SLDataType data);
//尾插
void SLPushBack(SeqList* psl, SLDataType data);
//中间插
void SLInsert(SeqList* psl, int pos, SLDataType data);

//打印
void SLPrint(SeqList* psl);
//头删
void SLPopFront(SeqList* psl);
//尾删
void SLPopBack(SeqList* psl);
//中间删 
void SLEarse(SeqList* psl, int pos);

//查询
int SLFind(SeqList* psl, SLDataType data);
// 修改
void SLModify(SeqList* psl, int pos, SLDataType data);
//销毁
void SLDestory(SeqList* psl);

实现文件

#include "SeqList.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

void SLInit(SeqList* psl)
{
	assert(psl);
	psl->array = (SLDataType*)malloc(sizeof(SLDataType) * 4);
	if (psl->array == NULL)
	{
		perror("malloc fail");
		return;
	}
	psl->capacity = 4;
	psl->size = 0;
}

//检查容量
void CheckCapc(SeqList* psl)
{
	assert(psl);

	if (psl->size == psl->capacity)
	{
		SLDataType* temp = (SLDataType*)realloc(psl->array, sizeof(SLDataType) * psl->capacity * 2);
		if (temp == NULL)
		{
			perror("realloc fail");
			return;
		}

		psl->array = temp;
		psl->capacity = psl->capacity * 2;

	}

}

void SLPushFront(SeqList* psl, SLDataType data)
{
	assert(psl);
	/*CheckCapc(psl);

	int end = psl->size - 1;
	while (end >= 0)
	{
		psl->array[end + 1] = psl->array[end];
		end--;
	}
		
	psl->array[0] = data;
	psl->size++;*/
	//调用中间插入
	SLInsert(psl, 0, data);
}

void SLPushBack(SeqList* psl, SLDataType data)
{
	assert(psl);
	/*CheckCapc(psl);
	psl->array[psl->size] = data;
	psl->size++;*/

	//调用中间插入
	SLInsert(psl, psl->size, data);
}

void SLInsert(SeqList* psl, int pos, SLDataType data)
{
	assert(psl);
	assert(pos >= 0 && pos <= psl->size);
	CheckCapc(psl);

	int end = psl->size - 1;
	while (end >= pos)
	{
		psl->array[end + 1] = psl->array[end];
		end--;
	}
	psl->array[pos] = data;
	psl->size++;
}

void SLPrint(SeqList* psl)
{
	assert(psl);

	for (int i = 0; i < psl->size; i++)
	{
		printf("%d ", psl->array[i]);
	}
	printf("\r\n");
}

void SLPopFront(SeqList* psl)
{
	assert(psl);
	assert(psl->size > 0);
	/*int start = 0;
	while (start < psl->size - 1)
	{
		psl->array[start] = psl->array[start + 1];
		start++;
	}

	psl->size--;*/
	SLEarse(psl, 0);
}

void SLPopBack(SeqList* psl)
{
	assert(psl);
	assert(psl->size > 0);
	psl->size--;
}

void SLEarse(SeqList* psl, int pos)
{
	assert(psl);
	assert(psl->size > 0);

	int start = pos + 1;
	while (start < psl->size)
	{
		psl->array[start - 1] = psl->array[start];
		start++;
	}

	psl->size--;
}

int SLFind(SeqList* psl, SLDataType data)
{
	assert(psl);
	int i = 0;
	for (; i < psl->size; i++)
	{
		if (psl->array[i] == data)
			return i;
	}

	return -1;
}

void SLModify(SeqList* psl, int pos, SLDataType data)
{
	assert(psl);
	assert(pos >= 0 && pos <= psl->size);

	psl->array[pos] = data;
}

void SLDestory(SeqList* psl)
{
	assert(psl);

	if (psl->array != NULL)
	{
		free(psl->array);
		psl->array = NULL;
	}
	psl->capacity = 0;
	psl->size = 0;
	psl = NULL;
}

主文件

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "SeqList.h"

int main()
{
	SeqList array;
	SLInit(&array);
	//增加
	SLPushBack(&array, 1);
	SLPushBack(&array, 2);
	SLPushBack(&array, 3);
	SLPushBack(&array, 4);
	SLPushBack(&array, 5);

	SLPushFront(&array, 6);
	SLPrint(&array);
	//删除
	SLPopBack(&array);
	SLPrint(&array);
	SLPopFront(&array);
	SLPrint(&array);
	SLInsert(&array, 4, 4);
	SLPrint(&array);
	//删除指定元素
	SLEarse(&array, 2);
	SLPrint(&array);
	SLInsert(&array, 4, 8);
	SLPrint(&array);

	int pos = SLFind(&array, 8);
	if (pos != -1)
	{
		SLModify(&array, pos, 10);
	}
	SLPrint(&array);
	SLDestory(&array);

	return 0;
}

传入顺序表指针的函数都需要检查一下指针是否为空,用断言直接报错的好处在于运行的时候哪里出问题报错提示很明显

菜单界面在调试阶段最好别加,影响调试效率,菜单界面也不是必须的

菜单项在添加数据的时候,如何判断输入数据结束了。用-1或某个值也可能遇到用户刚好需要存入-1的情况。这时可以先输入插入数据的数量,再逐个输入数据

当scanf接收输入失败的时候会卡住下次输入,如果不清空缓冲区,可能会无限读入,可以通过判断scanf返回值看是否输入成功

3. 练习

移除元素: https://leetcode.cn/problems/remove-element/

在这里插入图片描述

第一种:
暴力求解,遍历数组,遇到和值一样的,将后面的往前覆盖,继续查找
在这里插入图片描述
时间复杂度:O(N2)
空间复杂度: O(1)

第二种:
新建一个数组,遇到值和给定值不一样的放入新数组里
在这里插入图片描述
时间复杂度:O(N)
空间复杂度: 开辟了新数组, O(N)

第三种:
和第二种思路相似,但不开辟新数组,在原数组上修改。用两个下标,一个des,一个src,遇到和给定值不一样的,将des处值改为src的值,两个下标都增加1,遇到一样的,只增加src下标。当src遍历完数组,返回长度

在这里插入图片描述

int removeElement(int* nums, int numsSize, int val) {
    
    int sign1 = 0;
    int sign2 = 0;
    for(int i = 0; i < numsSize; i++)
    {
        if(nums[sign1] != val)
        {
            nums[sign2] = nums[sign1];
            sign1++;
            sign2++;
        }else
        {
            sign1++;
        }
    }

    return sign2;
}

合并两个有序数组
https://leetcode.cn/problems/merge-sorted-array/description/

在这里插入图片描述
暴力求解:

将两数组放在一起,然后排序

思路
依次比较两个数组,将值小的放入新数组,然后加下标,直到有一个数组遍历完,将剩下的放入新数组返回。这个思路需要一个新数组,如果不创建新数组,在数组1的基础上修改,如果还是这样比,在移动的过程中可能会覆盖原值。所以可以从后往前,也就是比最大的,将最大的放到最后一个下标,依次递减,如果数组1已经比完,将数组2剩下的拷进来,数组2比完,则已经排好序,不用动了
在这里插入图片描述

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
	  //记录比较下标
    int flag1 = m - 1;
    int flag2 = n - 1;
    //记录放值下标
    int cur = m + n - 1;
		
		//比较放哪个值
    while (flag1 >= 0 && flag2 >= 0)
        if (nums1[flag1] < nums2[flag2]) {
            nums1[cur--] = nums2[flag2];
            flag2--;
        } else {
            nums1[cur--] = nums1[flag1];
            flag1--;
        }

		//如果数组2没比完,将剩下的值放进来
        while (flag2 >= 0) {
            nums1[cur--] = nums2[flag2];
            flag2--;
         }
}
  • 24
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值