顺序表的介绍和实现

顺序表的介绍和实现

  • 线性表是我们认识的第一种数据结构,线性表其实包含有两种数据结构,一种是顺序表,一种是链表
  • 线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储
  • 线性表是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串
  • 顺序表的本质其实就是一个数组

顺序表

  • 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改
  • 顺序表又分为静态顺序表和动态顺序表,主要的区别还是在于存储元素个数的灵活性的问题;静态顺序表:使用定长数组存储元素,动态顺序表:使用动态开辟的数组存储
  • 静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,下面是静态顺序表
    在这里插入图片描述

程序的实现大致分为三个部分

SeqList.h
#pragma once   //防止文件被重复包含

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
//#define MAXSIZE 20
#define DefaultCapacity 20 
typedef int DataType;   //因为存储的可能不只是整形,所以使用通用的类型
//  SeqList存储在连续的空间之中  ---   数组
//静态顺序表
//struct SeqList
//{
//	DataType array[MAXSIZE];   //保存顺序表中有序元组的个数
//	int size;             //顺序表中有效元素的个数
//};
//动态顺序表
//所以结构体中的动态空间不能给死
typedef struct SeqList
{
	DataType* array;   //保存顺序表中有效元素个数
	int _size;         //记录有效元素的个数
	int _capacity;     //空间总大小
}SeqList;

void SeqListInit(SeqList* seq);  //用指针的原因是,结构体可能比较大
//利用传值的方式,就会有些浪费空间

void SeqListPrint(SeqList* seq);

void SeqListDestroy(SeqList* seq);  //动态开辟的空间需要手动的进行释放

void SeqListPushBack(SeqList* seq, DataType data);  //进行尾插的操作

void SeqListPopBack(SeqList* seq);   //尾删
  
void SeqListPushFront(SeqList* seq, DataType data);  //头插

void SeqListPopFront(SeqList* seq);   //头删

void SeqListInsert(SeqList* seq, int index, DataType data);//在任意位置进行插入

void SeqListErase(SeqList* seq, int index); //在任意位置进行删除

int SeqListFind(SeqList* seq, DataType data);    //查找元素

void SeqListRemove(SeqList* seq, DataType data);  //移除第一个值为data的元素

void SeqListRemoveAll(SeqList* seq, DataType data);  //移除所有值为data的元素

int SeqSize(SeqList* seq);  //获取顺序表中元素的个数

int SeqCapacity(SeqList* seq);  //获取顺序表的容量

int SeqListEmpty(SeqList* seq);   //判断顺序表是否为空

DataType SeqListFront(SeqList* seq);  //获取顺序表的第一个元素

DataType SeqListLast(SeqList* seq);   //获取顺序表的最后一个元素
SeqList.c
#include"SeqList.h"

static void CheckCapacity(SeqList *seq)
{
	assert(seq != NULL);
	if (seq->_size == seq->_capacity)
	{
		int newCapacity = 2 * DefaultCapacity;
		DataType* newArray = (DataType*)malloc(sizeof(DataType) * newCapacity);
		if (NULL == newArray)
		{
			assert(0);
			return ;
		}
		memcpy(newArray, seq->array, seq->_size * sizeof(DataType));
		//释放就空间
		free(seq->array);
		seq->array = newArray;
		seq->_capacity = newCapacity;
	}
}

void SeqListInit(SeqList* seq)
{
	assert(seq != NULL);  //先检测参数的合法性,然后再给出算法的功能
	seq->array = (DataType*)malloc(sizeof(DataType) * DefaultCapacity);
	if (NULL == seq->array)
	{
		assert(0);  //assert是调试宏,只有在Debug版本才能起作用
		return;
	}
	//如果if不成立,说明申请空间已经成功了
	seq->_size = 0;
	seq->_capacity = DefaultCapacity;
}

void SeqListDestroy(SeqList* seq)
{
	free(seq->array);
	seq->array = NULL;
	seq->_size = 0;
	seq->_capacity = 0;
}

void SeqListPushBack(SeqList* seq, DataType data)  //尾插
{
	assert(seq != NULL);
	CheckCapacity(seq);
	seq->array[seq->_size] = data;
	seq->_size++;
	//但是在动态顺序表中还需要考虑是否需要扩容的问题
	//看容量是否够用,然后,是否需要扩容
}

void SeqListPopBack(SeqList* seq)   //尾删
{
	assert(seq != NULL);
	if (0 == seq->_size)
		return;
	seq->_size--;
}

void SeqListPrint(SeqList* seq)
{
	assert(seq);
	int i = 0;
	for (i = 0; i < seq->_size; i++)
	{
		printf("%d ", seq->array[i]);
	}
	printf("\n");
}

void SeqListPushFront(SeqList* seq, DataType data)
{
	assert(seq != NULL);
	//还需要检测空间是否充足
	CheckCapacity(seq);
	//进行元素的插入
	for (int i = seq->_size-1; i >= 0; i--)
	{
		seq->array[i + 1] = seq->array[i];
	}
	seq->array[0] = data;
	seq->_size++;
}

void SeqListPopFront(SeqList* seq)
{
	assert(seq != NULL);
	if (0 == seq->_size)
		return;
	else
	{
		for (int i = 0; i <= seq->_size-2 ; i++)
		{
			seq -> array[i] = seq->array[i + 1];
		}
	}
	seq->_size--;
}

void SeqListInsert(SeqList* seq,int index,DataType data)
{
	assert(seq != NULL);
	//还需要判断一下所输入下标的合法性
	if (index<0 || index>seq->_size)
	{
		printf("所输入的下标为非法下标,请重新输入!");
		return;
	}
	//然后还需要检测容量是否够用
	CheckCapacity(seq);
	for (int i = seq->_size - 1; i >= index; i--)
	{
		seq->array[i + 1] = seq->array[i];
	}
	seq->array[index] = data;
	seq->_size++;
}

void SeqListErase(SeqList* seq, int index)
{
	assert(seq != NULL);
	if (index<0 || index>seq->_size)
	{
		printf("所输入的下标为非法下标,请重新输入!");
		return;
	}
	for (int i = index; i <= seq->_size - 2; i++)
	{
		seq->array[i] = seq->array[i + 1];
	}
	seq->_size--;
}

int SeqListFind(SeqList* seq, DataType data)
{
	assert(seq != NULL);
	for (int i = 0; i < seq->_size; i++)
	{
		if (seq->array[i] == data)
			return i;
	}
	return -1;
}

void SeqListRemove(SeqList* seq, DataType data)
{
	assert(seq != NULL);
	SeqListErase(seq, SeqListFind(seq, data));
}

void SeqListRemoveAll(SeqList* seq, DataType data)
{
	//但是这种方法的时间复杂度接近N^2
	assert(seq != NULL);
	int index = -1;
	while (-1 == SeqListFind(seq, data))
	{
		SeqListErase(seq, index);
	}
	//还可以通过一遍遍历,单独调用Erase
	//还可以通过提供辅助空间,此时空间复杂度为O(N),时间复杂度为0(N)
	/*
	int count=0;   //记录待删除元素的个数
	for(int i=0;i<seq->_size;i++)
	{
	  if(data==seq->array[i])
	     count++;
	  else
	     seq->array[i-cout]=seq->array[i];
     }
	 //这种方法的时间复杂度为O(N),空间复杂度为O(1)
	*/
}

int SeqListSize(SeqList* seq)
{
	assert(seq != NULL);
	return seq->_size;
}

int SeqListCapacity(SeqList* seq)
{
	assert(seq != NULL);
	return seq->_capacity;
}

int SeqListEmpty(SeqList* seq)
{
	assert(seq != NULL);
	if (0 == seq->_size)
		return 1;
	else
		return 0;
}

DataType SeqListFront(SeqList* seq)
{
	assert(seq != NULL);
	return seq->array[0];
}

DataType SeqListLast(SeqList* seq)
{
	assert(seq != NULL);
	return seq->array[seq->_size - 1];   //不能用前置--和后置--,使用的话,顺序表的元素个数就会少1
}

main.c

#include"SeqList.h"

int main()
{
	SeqList Seq;   //给一个顺序表的结构,也就是结构体类型的变量

	SeqListInit(&Seq);

	SeqListPushBack(&Seq, 1);
	SeqListPushBack(&Seq, 2);
	SeqListPushBack(&Seq, 3);
	SeqListPushBack(&Seq, 4);
	SeqListPushBack(&Seq, 5);

	SeqListPrint(&Seq);

	SeqListPopBack(&Seq);
	SeqListPopBack(&Seq);

	SeqListPrint(&Seq);

	SeqListPushFront(&Seq, 10);
	SeqListPushFront(&Seq, 20);
	SeqListPushFront(&Seq, 30);
	SeqListPushFront(&Seq, 40);
	SeqListPushFront(&Seq, 50);

	SeqListPrint(&Seq);

	SeqListPopFront(&Seq);
	SeqListPopFront(&Seq);
	SeqListPopFront(&Seq);

	SeqListPrint(&Seq);

	SeqListInsert(&Seq, 3, 46);

	SeqListPrint(&Seq);

	SeqListErase(&Seq,3);

	SeqListPrint(&Seq);

	SeqListFind(&Seq, 30);

	printf("%d\n", SeqListSize(&Seq));  //5
	printf("%d\n", SeqListCapacity(&Seq));  //20


	SeqListDestroy(&Seq);
	return 0;
}
相关OJ
题目一:移除元素

在这里插入图片描述

  • 拿到这个题目如如果忽略掉题目的要求的话,就是可以使用两个数组来对这个问题进行求解的,把等于那个元素的值的元素放在另外一个数组,剩下的元素就是符合条件的元素,可以直接返回另一个数组,就是满足条件的,但是这样不符合题目的要求,这种算法的时间复杂度和空间复杂度都是O(N),所以相当于是用空间换时间的方法
  • 另一种解法,其实就是在原先的数组中进行相应的操作,使用两个指针进行来进行求解
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int n = nums.size();
        int left = 0;
        for (int right = 0; right < n; right++) {
            if (nums[right] != val) {
                nums[left] = nums[right];
                left++;
            }
        }
        return left;
    }
};
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值