IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 数据结构-第2节-顺序表和链表 -> 正文阅读

[数据结构与算法]数据结构-第2节-顺序表和链表

作者:recommend-item-box type_blog clearfix

1.线性表

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


2.顺序表

2.1.概念及结构

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

1. 静态顺序表:使用定长数组存储元素

要求:存储的数据从0开始,依次连续存储

问题:内存开小了不够用,开大了存在浪费(不实用)

2.动态顺序表:使用动态开辟的数组存储

要求:存储的数据从0开始,依次连续存储

?注:指针a负责接收动态开辟出来的空间地址

2.2.接口实现

test.c文件:

#define _CRT_SECURE_NO_WARNINGS 1

#include "SeqList.h"

void TestSeqList1()
{
	SeqList s;
	SeqListInit(&s);
	SeqListPushBack(&s, 1);
	SeqListPushBack(&s, 2);
	SeqListPushBack(&s, 3);
	SeqListPushBack(&s, 4);
	SeqListPushBack(&s, 5);
	SeqListPushBack(&s, 0);
	SeqListPrint(&s);

	SeqListPopBack(&s);
	SeqListPopBack(&s);
	SeqListPrint(&s);

	SeqListPopBack(&s);
	SeqListPopBack(&s);
	SeqListPopBack(&s);
	SeqListPopBack(&s);
	SeqListPopBack(&s);
	SeqListPopBack(&s);
	SeqListPopBack(&s);
	SeqListPopBack(&s);
	SeqListPrint(&s);

	SeqListPushBack(&s, 10);
	SeqListPushBack(&s, 20);
	SeqListPrint(&s);

}

void TestSeqList2()
{

	SeqList s;
	SeqListInit(&s);
	SeqListPushBack(&s, 1);
	SeqListPushBack(&s, 2);
	SeqListPushBack(&s, 3);
	SeqListPushBack(&s, 4);
	SeqListPushFront(&s, 0);
	SeqListPushFront(&s, -1);
	SeqListPrint(&s);

	SeqListPopFront(&s);
	SeqListPopFront(&s);
	SeqListPopFront(&s);
	SeqListPopFront(&s);
	SeqListPopFront(&s);
	SeqListPrint(&s);

	SeqListPopFront(&s);
	SeqListPrint(&s);

	SeqListPopFront(&s);
	SeqListPopFront(&s);
	SeqListPushFront(&s, 0);
	SeqListPushFront(&s, -1);
	SeqListPrint(&s);
}

void TestSeqList3()
{
	SeqList s;
	SeqListInit(&s);
	SeqListPushBack(&s, 1);
	SeqListPushBack(&s, 2);
	SeqListPushBack(&s, 3);
	SeqListPushBack(&s, 4);
	SeqListPrint(&s);

	SeqListInsert(&s, 10, 100);
	SeqListInsert(&s, 1, 20);
	SeqListInsert(&s, 5, 50);
	SeqListInsert(&s, 0, 50);

	SeqListPrint(&s);

	SeqListDestroy(&s);
}

void TestSeqList4()
{
	SeqList s;
	SeqListInit(&s);
	SeqListPushBack(&s, 1);
	SeqListPushBack(&s, 2);
	SeqListPushBack(&s, 3);
	SeqListPushBack(&s, 4);
	SeqListPushBack(&s, 5);
	SeqListPrint(&s);

	SeqListErase(&s, 4);
	SeqListPrint(&s);

	SeqListErase(&s, 0);
	SeqListPrint(&s);

	SeqListErase(&s, 1);
	SeqListPrint(&s);
}

void TestSeqList5()
{
	SeqList s;
	SeqListInit(&s);
	SeqListPushBack(&s, 1);
	SeqListPushBack(&s, 2);
	SeqListPushBack(&s, 3);
	SeqListPushBack(&s, 4);
	SeqListPushBack(&s, 5);
	SeqListPushFront(&s, -1);
	SeqListPushFront(&s, -2);
	SeqListPrint(&s);

	SeqListPopFront(&s);
	SeqListPopFront(&s);
	SeqListPopBack(&s);
	SeqListPopBack(&s);
	SeqListPrint(&s);

	SeqListDestroy(&s);
}

int main()
{

	TestSeqList5();

	return 0;
}

SeqList.h文件:

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* a;
	int size;     // 存储数据个数
	int capacity; // 存储空间大小
}SL, SeqList;


//打印内存数据
void SeqListPrint(SeqList* psl);


//初始化内存数据
void SeqListInit(SeqList* psl);
//释放内存数据
void SeqListDestroy(SeqList* psl);


//检查内存容量
void SeqListCheckCapacity(SeqList* psl);


//尾插
void SeqListPushBack(SeqList* psl, SLDataType x);
//尾删
void SeqListPopBack(SeqList* psl);


//头插
void SeqListPushFront(SeqList* psl, SLDataType x);
//头删
void SeqListPopFront(SeqList* psl);


// 任意插
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x);
// 任意删
void SeqListErase(SeqList* psl, size_t pos);


// 顺序表查找
int SeqListFind(SeqList* psl, SLDataType x);

SeqList.c文件:

#define _CRT_SECURE_NO_WARNINGS 1

#include "SeqList.h"

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

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


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

	psl->a = NULL;
	psl->size = 0;
	psl->capacity = 0;
}


void SeqListDestroy(SeqList* psl)
{
	assert(psl);
	free(psl->a);
	psl->a = NULL;
	psl->capacity = psl->size = 0;
}


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

	// 如果满了,我们要扩容
	if (psl->size == psl->capacity)
	{
		size_t newCapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;
		SLDataType* tmp = realloc(psl->a, sizeof(SLDataType) * newCapacity);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}
		else
		{
			psl->a = tmp;
			psl->capacity = newCapacity;
		}
	}
}


void SeqListPushBack(SeqList* psl, SLDataType x)
{
	assert(psl);

	//方法1:尾插功能实现代码
	/*SeqListCheckCapacity(psl);

	psl->a[psl->size] = x;
	psl->size++;*/

	//方法2:用任意插功能实现尾插
	SeqListInsert(psl, psl->size, x);
}


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

	//方法1:尾删功能实现代码
	//psl->a[psl->size - 1] = 0;
	/*if (psl->size > 0)
	{
		psl->size--;
	}*/

	//方法2:用任意删功能实现尾删
	SeqListErase(psl, psl->size - 1);
}


void SeqListPushFront(SeqList* psl, SLDataType x)
{
	assert(psl);

	//方法1:头插功能实现代码
	//SeqListCheckCapacity(psl);
	 挪动数据,腾出头部空间
	//int end = psl->size - 1;
	//while (end >= 0)
	//{
	//	psl->a[end + 1] = psl->a[end];
	//	--end;
	//}
	//psl->a[0] = x;
	//psl->size++;

	//方法2:用任意插功能实现头插
	SeqListInsert(psl, 0, x);
}

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

	//方法1:头删功能实现代码
	// 挪动数据覆盖删除
	/*if (psl->size > 0)
	{
		int begin = 1;
		while (begin < psl->size)
		{
			psl->a[begin - 1] = psl->a[begin];
			++begin;
		}

		--psl->size;
	}*/

	//方法2:用任意删功能实现头删
	SeqListErase(psl, 0);
}


void SeqListInsert(SeqList* psl, size_t pos, SLDataType x)
{
	assert(psl);

	// pos数值温和检查
	if (pos > psl->size)
	{
		printf("pos 越界:%d\n", pos);
		return;
		//exit(-1);
	}
	// pos数值暴力检查
	//assert(pos <= psl->size);

	SeqListCheckCapacity(psl);

	//交换方法1(pos必须强制类型转换)
	//int end = psl->size - 1;
	//while (end >= (int)pos)
	//{
	//	psl->a[end + 1] = psl->a[end];
	//	--end;
	//}

	//交换方法2
	size_t end = psl->size;
	while (end > pos)
	{
		psl->a[end] = psl->a[end - 1];
		--end;
	}

	psl->a[pos] = x;
	psl->size++;
}


void SeqListErase(SeqList* psl, size_t pos)
{
	assert(psl);
	assert(pos < psl->size);

	size_t begin = pos + 1;
	while (begin < psl->size)
	{
		psl->a[begin - 1] = psl->a[begin];
		++begin;
	}

	psl->size--;
}


int SeqListFind(SeqList* psl, SLDataType x)
{
	assert(psl);

	for (int i = 0; i < psl->size; ++i)
	{
		if (psl->a[i] == x)
		{
			return i;
		}
	}

	return -1;
}

注:

1.传参数的时候不要传值调用(如下图所示),因为形参是实参的一份临时拷贝,对形参修改并不会影响实参,并且结构体传值调用会消耗大量的内存空间,因此要传值调用

2.系统对于越界的查询其实是抽查,有时候越界了但不一定能检查出来,就像查酒驾一样,不一定会被查到,但是我们一定不能酒驾

3.可以看出头插和头删时间复杂度为O(N),尾插和尾删时间复杂度为O(1),因此尽量使用尾插和尾删,不到万不得已不要使用头插和头删

4.静态的数组是在操作结束的时候就检查越界,动态开辟的内存只有在free的时候才会检查越界,如果不写free系统不会检查。系统在调试的时候如果调试到free进行报错,如果空间地址起始没有写错的话,那就是前面有越界的情况,这是一个经典的问题

5.尾插可以用任意位置插来实现(pos=size),头插可以用任意位置插来实现(pos=0)

? ?尾删可以用任意位置删来实现(pos=size-1),头删可以用任意位置删来实现(pos=0)

6.可以自己尝试一下给各功能写一个菜单,如下图所示,注意写菜单最好是所有功能都实现了再写菜单因为一上来就写菜单不好调试

2.3.顺序表相关练习

练习1:

习题链接:27. 移除元素 - 力扣(LeetCode) (leetcode-cn.com)

思路:

1.每查找到一个val,挪动后面的数据向前进行覆盖

时间复杂度(最坏的情况,即全是val):O(N^{2})? ? ?空间复杂度:O(1)

2.把不是val的值拷贝到新数组中,然后将新数组中的值拷贝回原数组

时间复杂度:O(N)? ? ?空间复杂度:O(N)

3.使用两个指针src和dst,src++往后遍历,如果src解引用不是val就放到dst中然后dst++

时间复杂度:O(N)? ? ?空间复杂度:O(1)

代码:(思路三代码实现)

练习2:

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-17 22:25:52  更:2022-03-17 22:27:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 11:46:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码