C++数据结构 —— 顺序表

在这里插入图片描述

在这里插入图片描述

🎁个人主页:工藤新一¹

🔍系列专栏:C++面向对象(类和对象篇)

​ 🌟心中的天空之城,终会照亮我前方的路

🎉欢迎大家点赞👍评论📝收藏⭐文章

顺序表

一、线性表

  • 线性表(linear list)是 n 个具有相同特性的数据元素的有限序列,其是一种被广泛使用的数据结构,常见的**线性表:**顺序表、链表、栈、队列、字符串……
    • 逻辑结构上:线性结构,是一条连续的直线(人为 想象出的结构)
    • 物理结构上:在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储

二、顺序表

1.概念与结构

  • 概念:顺序表是用一段用物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。另外,数组最基础的数据结构顺序表底层结构就是在数组的基础上进行增删查改

2.顺序表的分类

2.1静态顺序表
  • 在编译阶段,就指定了顺序表的空间大小
    • eg:int arr[10];
    • 静态数组的大小长度是固定的
  • 适用于数据元素固定的情况
C++
    //静态顺序表
    typedef int SLDataType;--->取别名的意义:为了方便后期的对于数组类型的一键修改(Ctrl f)
        
	#define N 7

    typedef struct SeqList--->使用结构体包装数组和整形变量(定义不同类型的变量)
    {
		SLDataType arr[N];--->定长数组
        int size;--->有效数据个数
    }SL;--->SeqList的别名
  • 静态顺序表的缺陷:空间给少了不够用,给多了造成空间上的浪费

在这里插入图片描述


2.2动态顺序表
  • 在堆区动态开辟的数据
    • int arr = new int( );*
    • 动态顺序表底层的数组空间会不断的变化
C++
    //动态顺序表 -- 按需申请
    typedef struct SeqList
    {
        SLDataType* arr;--->维护堆区
        int size;
        int capacity;--->空间容量
    }SL;

在这里插入图片描述


3.动态顺序表的创建

  • .cpp文件中
C++
    #include"Sqlist.h"
	
    //对顺序表进行初始化 - 实现
	void SLInit(SL s) 
	{
		s.arr = NULL;
		s.size = s.capacity = 0;
	}
  • .h文件
C++
    #pragma once
	#include<iostream>

	//定义动态顺序表的结构
	typedef int SLDataType;

	typedef struct SeaList 
	{
		SLDataType* arr;
		int size;//有效元素个数
		int capacity;//空间容量
	}SL;

	//对顺序表进行初始化 - 声明
	void SLInit(SL s);
  • test.cpp
C++
    #include"Sqlist.h"

	void test01(){
	SL s1;
	SLInit(s1);
	}
	int main(){
	test01();
	return 0;
	}

3.1值传递的局限性

当代码运行时,所出现的小问题

在这里插入图片描述

在这里插入图片描述

这里就相当于:
int a;
func(a);--->a未被初始化,就对a进行传值操作


3.2地址传递
  • .cpp
C++
    #include"Sqlist.h"

	void test01(){
		SL s1;

		SLInit(&s1);--->地址传递	
	}

	int main(){test01();return 0;}
  • .h文件
C++
    #pragma once
	#include<iostream>

	typedef int SLDataType;

	typedef struct SeaList 
	{
		SLDataType* arr;
		int size;
		int capacity;
	}SL;

	void SLInit(SL* ps);--->指针接收地址
  • test.cpp文件
C++
	#include"Sqlist.h"
	
	void SLInit(SL* ps)--->指针接收地址
	{
		ps->arr = NULL;
		ps->size = ps->capacity = 0;	
	}

在这里插入图片描述


3.3尾插操作
  • .h文件
C++
    void SLPushBack(SL* ps, SLDataType x);
  • test.cpp文件
C++
	void SLPushBack(SL* ps, SLDataType x)
	{
    //判断空间是否足够 - 拷贝旧数据,释放旧空间
    	if(ps->size == ps->capacity)
        {
            //判断capacity是否未为0,因为 0 乘任何数都是0,会导致扩增失败
            //ps->capacity == 0吗?如果是,newCapacity = 4
			int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
            //强制转换,扩充的对象,增加字节大小
            SLDataType* temp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
            
            if(temp == NULL) 
            {
				perror("realloc fail!");
                exit(1);
            }
            ps->arr = temp;
            ps->capacity = newCapacity;
        }
    //空间足够的情况下,直接插入
    	ps->arr[ps->size++] = x;
	}

3.3.1调试(Matter)

3.4尾插 + 头插
//将重复的代码封装到单独的函数中,方便以后使用
//判断空间是否足够的函数
void SLCheckCapacity(SL* ps)
{
    //判断空间是否足够 - 拷贝旧数据,释放旧空间
    if (ps->size == ps->capacity)
    {
        //ps->capacity == 0吗?如果是,newCapacity = 4
        int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
        //强制转换,扩充对象,增加字节大小
        SLDataType* temp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));

        if (temp == NULL)
        {
            perror("realloc fail!");
            exit(1);
        }
        ps->arr = temp;
        ps->capacity = newCapacity;
    }
}

//尾插
void SLPushBack(SL* ps, SLDataType x)
{
    assert(ps != NULL);
    //判断空间是否足够
    SLCheckCapacity(ps);
    ps->arr[ps->size++] = x;
}

//头插
void SLPushFront(SL* ps, SLDataType x)
{
    //if (ps == NULL) return;// 温柔

    assert(ps != NULL);//断言:ps不能为NULL
    //判断空间是否足够
    SLCheckCapacity(ps);

    for (int i = ps->size - 1; i >= 0; i--)
    {
        ps->arr[i + 1] = ps->arr[i];
    }
    ps->arr[0] = x;
    ps->size++;
}

3.5头删与尾删
  • .cpp文件
void SLPrint(SL* ps)
{
    for (int i = 0; i < ps->size; i++)
    {
        cout << ps->arr[i] << " ";
    }
    cout << endl;
}

//尾删
void SLPopBack(SL* ps)
{
    //ps != NULL
    //ps->size != 0(表中元素不为0)
    assert(ps && ps->size);
    ps->size--;
}

//头删
void SLPopFront(SL* ps)
{
    assert(ps && ps->size);
    for (int i = 0; i < ps->size - 1; i++)
    {
        ps->arr[i] = ps->arr[i + 1];
    }
    ps->size--;
} 

  • test.cpp
void test01()
{
	SL s1;

	SLInit(&s1);

	SLPushBack(&s1, 1);
	SLPushBack(&s1, 2);
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushBack(&s1, 5);
	SLPrint(&s1);

	/*
	SLPushFront(&s1, 1);
	SLPushFront(&s1, 2);
	SLPushFront(&s1, 3);
	SLPushFront(&s1, 4);
	SLPushFront(NULL, 1);--->false,断言报错
	*/

	SLPopBack(&s1);
	SLPopBack(&s1);
	SLPrint(&s1);

	SLPopFront(&s1);
	SLPopFront(&s1);
	SLPrint(&s1);

3.6任意位置插入、删除
#include"Sqlist.h"

void SLInit(SL* ps) 
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

void SLPrint(SL* ps)
{
    for (int i = 0; i < ps->size; i++)
    {
        cout << ps->arr[i] << " ";
    }
    cout << endl;
}

//将重复的代码封装到单独的函数中,方便以后使用
//判断空间是否足够的函数
void SLCheckCapacity(SL* ps)
{
    //判断空间是否足够 - 拷贝旧数据,释放旧空间
    if (ps->size == ps->capacity)
    {
        //ps->capacity == 0吗?如果是,newCapacity = 4
        int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
        //强制转换,扩充对象,增加字节大小
        SLDataType* temp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));

        if (temp == NULL)
        {
            perror("realloc fail!");
            exit(1);
        }
        ps->arr = temp;
        ps->capacity = newCapacity;
    }
}

//尾插
void SLPushBack(SL* ps, SLDataType x)
{
    assert(ps != NULL);
    //判断空间是否足够
    SLCheckCapacity(ps);
    ps->arr[ps->size++] = x;
}

//头插
void SLPushFront(SL* ps, SLDataType x)
{
    //if (ps == NULL) return;// 温柔

    assert(ps != NULL);
    //判断空间是否足够
    SLCheckCapacity(ps);

    for (int i = ps->size - 1; i >= 0; i--)
    {
        ps->arr[i + 1] = ps->arr[i];
    }
    ps->arr[0] = x;
    ps->size++;
}

//尾删
void SLPopBack(SL* ps)
{
    //ps != NULL
    //ps->size != 0(表中元素不为0)
    assert(ps && ps->size);
    ps->size--;
}

//头删
void SLPopFront(SL* ps)
{
    assert(ps && ps->size);
    for (int i = 0; i < ps->size - 1; i++)
    {
        ps->arr[i] = ps->arr[i + 1];
    }
    ps->size--;
} 


void SLInsert(SL* ps, int pos, SLDataType x)
{
    assert(ps);
    assert(pos >= 0 && pos <= ps->size);
    SLCheckCapacity(ps);
    for (int i = ps->size - 1; i >= pos; i--)
    {    
        ps->arr[i + 1] = ps->arr[i];
    }
    ps->arr[pos] = x;
    ps->size++;
}

void SLErase(SL* ps, int pos)
{

    for (int i = pos; i < ps->size - 1; i++)
    {
        ps->arr[i] = ps->arr[i + 1];
    }
    ps->size--;
}

3.7代码总实现
  • .h头文件
#pragma once
#include<iostream>
using namespace std;

#include<stdlib.h>//realloc,头文件
#include<cassert>

//定义动态顺序表的结构

typedef int SLDataType;

typedef struct SeqList 
{
	SLDataType* arr;
	int size;//有效元素个数
	int capacity;//空间容量
}SL;

//对顺序表进行初始化
void SLInit(SL* ps);//地址传递,指针接收,ps 相当于 实例化的对象

//输出函数
void SLPrint(SL* ps);

//销毁 - 顺序表的销毁
void SLDestory(SL* ps);

//尾插 - 向顺序表中插入元素 x(插入元素的数据类型,要与数组一致) 
void SLPushBack(SL* ps, SLDataType x);

//头插
void SLPushFront(SL* ps, SLDataType x);

//查数组容量
void SLCheckCapacity(SL* ps);

//尾删
void SLPopBack(SL* ps);

//头删
void SLPopFront(SL* ps);

//在之前插入
void SLInsert(SL* ps, int pos, SLDataType x);

//删除指定位置元素
void SLErase(SL* ps, int pos);

//查找元素
int SLFind(SL* ps, SLDataType x);

  • .cpp文件
#include"Sqlist.h"

void SLInit(SL* ps) 
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

void SLPrint(SL* ps)
{
    for (int i = 0; i < ps->size; i++)
    {
        cout << ps->arr[i] << " ";
    }
    cout << endl;
}

//将重复的代码封装到单独的函数中,方便以后使用
//判断空间是否足够的函数
void SLCheckCapacity(SL* ps)
{
    //判断空间是否足够 - 拷贝旧数据,释放旧空间
    if (ps->size == ps->capacity)
    {
        //ps->capacity == 0吗?如果是,newCapacity = 4
        int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
        //强制转换,扩充对象,增加字节大小
        SLDataType* temp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));

        if (temp == NULL)
        {
            perror("realloc fail!");
            exit(1);
        }
        ps->arr = temp;
        ps->capacity = newCapacity;
    }
}

//尾插
void SLPushBack(SL* ps, SLDataType x)
{
    assert(ps != NULL);
    //判断空间是否足够
    SLCheckCapacity(ps);
    ps->arr[ps->size++] = x;
}

//头插
void SLPushFront(SL* ps, SLDataType x)
{
    //if (ps == NULL) return;// 温柔

    assert(ps != NULL);
    //判断空间是否足够
    SLCheckCapacity(ps);

    for (int i = ps->size - 1; i >= 0; i--)
    {
        ps->arr[i + 1] = ps->arr[i];
    }
    ps->arr[0] = x;
    ps->size++;
}

//尾删
void SLPopBack(SL* ps)
{
    //ps != NULL
    //ps->size != 0(表中元素不为0)
    assert(ps && ps->size);
    ps->size--;
}

//头删
void SLPopFront(SL* ps)
{
    assert(ps && ps->size);
    for (int i = 0; i < ps->size - 1; i++)
    {
        ps->arr[i] = ps->arr[i + 1];
    }
    ps->size--;
} 


void SLInsert(SL* ps, int pos, SLDataType x)
{
    assert(ps);
    assert(pos >= 0 && pos <= ps->size);
    SLCheckCapacity(ps);
    for (int i = ps->size - 1; i >= pos; i--)
    {    
        ps->arr[i + 1] = ps->arr[i];
    }
    ps->arr[pos] = x;
    ps->size++;
}

void SLErase(SL* ps, int pos)
{
    assert(ps);
    assert(pos >= 0 && pos < ps->size);
    for (int i = pos; i < ps->size - 1; i++)
    {
        ps->arr[i] = ps->arr[i + 1];
    }
    ps->size--;
}

int SLFind(SL* ps, SLDataType x)
{
    assert(ps);
    for (int i = 0; i < ps->size; i++)
    {
        if (ps->arr[i] == x) return i;
    }

    //未找到
    return -1;
}

void SLDestory(SL* ps)
{
    assert(ps);
    //如果ps->arr不为空
    if (ps->arr)
        free(ps->arr);

    ps->arr = NULL;//将释放完毕的指针置为空,防止称为野指针
    //恢复初始化
    ps->size = ps->capacity = 0;

}

  • tes.cpp
#include"Sqlist.h"

void test01()
{
	SL s1;

	SLInit(&s1);

	SLPushBack(&s1, 1);
	SLPushBack(&s1, 2);
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushBack(&s1, 5);
	SLPrint(&s1);

	/*
	SLPushFront(&s1, 1);
	SLPushFront(&s1, 2);
	SLPushFront(&s1, 3);
	SLPushFront(&s1, 4);
	SLPushFront(NULL, 1);*/


	SLInsert(&s1, 0, 100);
	SLPrint(&s1);

	if (SLFind(&s1, 90) != -1) cout << "找到元素啦" << endl;
	else cout << "未找到!" << endl;
	

	SLDestory(&s1);
}
int main()
{
	test01();
	return 0;
}

在这里插入图片描述

🌟 各位看官好,我是工藤新一¹呀~

🌈 愿各位心中所想,终有所致!

评论 32
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值