【ONE·Data || 顺序表】

news2024/11/24 12:55:56

总言

  数据结构基础:顺序表模拟实现。
  

文章目录

  • 总言
  • 1、顺序表各接口功能实现描述
    • 1.1、如何创建一个顺序表?
    • 1.2、如何初始化顺序表:SLInit
    • 1.3、顺序表的尾插、头插
      • 1.3.1、顺序表尾插1.0:SLPushBack
      • 1.3.2、顺序表头插1.0:SLPushFront
      • 1.3.3、辅助扩容函数:SLCheckCapacity
        • 1.3.3.1、基本说明
        • 1.3.3.2、基于辅助扩容函数的头插尾插2.0
    • 1.4、顺序表的尾删、头删
      • 1.4.1、顺序表尾删:SLPopBack
      • 1.4.2、顺序表头删:SLPopFront
      • 1.4.3、关于结构体指针的检查说明
    • 1.5、顺序表打印、顺序表销毁
      • 1.5.1、顺序表打印:SLPrint
      • 1.5.2、顺序表销毁:SLDestroy
    • 1.6、顺序表在pos位置插入、删除
      • 1.6.1、顺序表在pos位置插入:SLInsert
      • 1.6.2、顺序表头插、尾插实现3.0
      • 1.6.3、顺序表在pos位置删除:SLErase
      • 1.6.4、顺序表头删、尾删实现3.0
    • 1.7、顺序表查找、修改
      • 1.7.1、顺序表查找:SLFind
      • 1.7.2、顺序表修改:SLModify
  • 2、总体
    • 2.1、Seqlist.h
    • 2.2、SList.c
    • 2.3、Test.c
  • 3、相关练习
    • 3.1、移除元素
    • 3.2、删除有序数组中的重复项
    • 3.3、合并两个有序数组

  
  

1、顺序表各接口功能实现描述

1.1、如何创建一个顺序表?

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

struct SeqList
{
	int data[100];//数组,顺序表一部分,用于存储数据
	int size;//大小,用于统计顺序表中元素个数
};

  上述只是一个基本雏形,因为还需要完善和修改。
  问题一:int data[100];顺序表存储的数据类型、数据大小被固定。
  
  1)、两种顺序表结构
在这里插入图片描述

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

#define N 100
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType data[N];
	size_t size;
}SL;

  缺点:定长数组长度固定,若N太小,可能不满足实际存储所需大小,若N太大,当实际存储数目相对很小时,会造成空间浪费。即这种以定长数组来实现的静态顺序表,一定程度上不能满足实际使用中运用自如的多种场景。
  
  
  动态顺序表:使用动态开辟的数组存储。

typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* data;//用于存储数据的数组,指向动态开辟空间的指针
	size_t size;//顺序表中实际数据个数
	size_t capacity;//顺序表容量空间大小
}SL;//为了便于书写而重命名

  其它说明:
  typedef int SLDataType;:使用typedef重定义数组类型,其目的是方便后续更换类型,此方法需要学习。
  
  

1.2、如何初始化顺序表:SLInit

  写法一:在初始化时置空,后续需要存储数据时再动态申请内存空间。

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

  其它说明:
  SL* ps:此处使用指针,是因为自定义函数中要改变实参数据,则需要址传递。
  
  
  

1.3、顺序表的尾插、头插

1.3.1、顺序表尾插1.0:SLPushBack

  1)、实现说明
  简介:顺序表尾插,即在顺序表末尾(数组末)插入一个新的数据。但需要注意容量空间问题:一初始插入未扩容时、其二为容量空间已满时。

void SLPushBack(SL* ps, SLDataType val)
{
	//检查	
	if (ps->capacity == ps->size)
	{
		size_t newcapacity = (ps->capacity == 0) ? (4) : (ps->capacity * 2);
		SLDataType* tmpdata = (SLDataType*)realloc(ps->data, newcapacity * sizeof(SLDataType));
		if (tmpdata == NULL)//检查
		{
			perror("realloc");
			return 1;
		}
		ps->capacity = newcapacity;
		ps->data = tmpdata;
	}
	//尾插
	ps->data[ps->size] = val;
	ps->size++;
}

  if (ps->capacity == ps->size):这里一次检查了两种情况:即初始化为NULL时,容量空间已满时;
  
  
  2)、测试检查

void test1()
{
	SL s1;
	SLInit(&s1);
	SLPushBack(&s1, 1);
	SLPushBack(&s1, 2);
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushBack(&s1, 5);
	SLPrint(&s1);
}

int main(void)
{
	test1();
	return 0;
}

  
  
  

1.3.2、顺序表头插1.0:SLPushFront

  1)、实现说明

  简介:顺序表头插,即在顺序表头部插入一个新的数据。由于此处顺序表是由数组实现的,数组在内存空间中连续存储,因此要头插一个新的数据,即意味着在数组空间足够的情况下,将原先数据都往后挪动一个位置。
  
  需要注意的细节
  1、保证顺序表空间足够(数组空间),则需要在每次使用头插函数时,都进行扩容检查。
  2、如何挪动数组数据?为了保证数组元素不被覆盖,在内存空间充裕的情况下,从后往前(先挪动后面的数据,再挪动前面的数据)。
  3、头插函数实际可通过pos位置插入函数实现(后续内容)。

void SLPushFront(SL* ps, SLDataType val)
{
	//容量检查
	if (ps->capacity == ps->size)
	{
		size_t newcapacity = (ps->capacity == 0) ? (4) : (ps->capacity * 2);
		SLDataType* tmpdata = (SLDataType*)realloc(ps->data, newcapacity * sizeof(SLDataType));
		if (tmpdata == NULL)//动态申请检查
		{
			perror("realloc");
			return 1;
		}
		ps->capacity = newcapacity;
		ps->data = tmpdata;
	}

	//数据挪动
	int end = ps->size;
	while (end >= 1)
	{
		ps->data[end] = ps->data[end - 1];
		end--;
	}

	//头插
	ps->data[0] = val;
	ps->size++;
}

  需要注意:挪动数据中的写法不唯一,只要保证先挪动后面的数据,再挪动前面的数据即可。
  
  
  2)、测试检查

void test2()
{
	SL s1;
	SLInit(&s1);
	SLPushFront(&s1, 1);
	SLPushFront(&s1, 2);
	SLPushFront(&s1, 3);
	SLPushFront(&s1, 4);
	SLPushFront(&s1, 5);
	SLPrint(&s1);
}

int main(void)
{
	test2();
	return 0;
}

  
  
  

1.3.3、辅助扩容函数:SLCheckCapacity

1.3.3.1、基本说明

  1)、问题引入
  在1.3.1和1.3.2中,进行数据插入时我们都进行了容量检查,因此,可以考虑将此部分内容单独拎出,写成一个独立的函数。
  
  2)、相关实现
  1、扩容检查分为两种情况,其一为首次使用顺序表(capacity=0),其二为顺序表容量空间满时(capacity≠0, but capacity=size)。
  2、使用realloc函数而未用malloc函数,是根据realloc函数的特性:第一形参为空指针NULL时,功能等同于malloc;第二形参为0,等同于free将释放内存块。

void SLCheckCapacity(SL* ps)
{
	//容量检查
	if (ps->capacity == ps->size)
	{
		size_t newcapacity = (ps->capacity == 0) ? (4) : (ps->capacity * 2);
		SLDataType* tmpdata = (SLDataType*)realloc(ps->data, newcapacity * sizeof(SLDataType));
		if (tmpdata == NULL)//动态申请检查
		{
			perror("realloc");
			return 1;
		}
		ps->capacity = newcapacity;
		ps->data = tmpdata;
	}

}

  
  
  

1.3.3.2、基于辅助扩容函数的头插尾插2.0

  1)、尾插实现2.0

void SLPushBack(SL* ps, SLDataType val)
{
	SLCheckCapacity(ps);
	ps->data[ps->size] = val;
	ps->size++;
}

  
  
  2)、头插实现2.0

void SLPushFront(SL* ps, SLDataType val)
{
	//容量检查
	SLCheckCapacity(ps);

	//数据挪动
	int end = ps->size;
	while (end >= 1)
	{
		ps->data[end] = ps->data[end - 1];
		end--;
	}

	//头插
	ps->data[0] = val;
	ps->size++;
}

  
  
  

1.4、顺序表的尾删、头删

1.4.1、顺序表尾删:SLPopBack

  1)、实现说明
  简介:顺序表尾删,即删除顺序表最末尾的数据

void SLPopBack(SL* ps)
{
	assert(ps->size > 0);
	ps->size--;
}

  注意事项:
  1、关于是否要对被删除数据做处理?
  实际上没有必要,例如,将被删除数据赋值为-1以此来表示该数据不存在,但也会有-1本身就是顺序表中一个数据的情况,即没有多余数值可提供该需求。
  因此实际操作中只需要将size数据实际个数做出更改即可。以此达到访问不到顺序表最末尾数据的效果。

  2、对size变量的细节处理?
  size在顺序表中表示实际数据个数,通常实际使用中有范围下限(最小值),因此使用尾删操作时,不能无限删下去,这样会造成size变为负值,而以负值访问数组是一种越界情况。
  因此尾删时需要对数据个数做检查。

  ps:此处关于越界不报错的原因:
  大概几率下,malloc等出错,在free处才显示报错。此外,关于越界是否报错,取决于编译器,系统对越界的检查,属于设岗抽查,类似于交警拦违规驾驶。
  
  
  2)、测试检查

void test3()//验证尾删
{
	SL s1;
	SLInit(&s1);
	SLPushFront(&s1, 1);
	SLPushFront(&s1, 2);
	SLPushFront(&s1, 3);
	SLPushFront(&s1, 4);
	SLPushFront(&s1, 5);
	SLPrint(&s1);

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

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

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

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

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

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

}

在这里插入图片描述
  
  
  

1.4.2、顺序表头删:SLPopFront

  1)、实现说明
  顺序表头删和尾删需要注意的细节点大致相同,只是头删需要涉及数据挪动问题。

void SLPopFront(SL* ps)
{
	assert(ps->size > 0);
	//挪动数据
	int begin = 1;
	while(begin < ps->size)
	{
		ps->data[begin-1] = ps->data[begin];
		begin++;
	}
	//数值矫正
	ps->size--;
}

  
  
  2)、测试检查

void test4()
{
	SL s1;
	SLInit(&s1);
	SLPushFront(&s1, 1);
	SLPushFront(&s1, 2);
	SLPushFront(&s1, 3);
	SLPushFront(&s1, 4);
	SLPushFront(&s1, 5);
	SLPrint(&s1);

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

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

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

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

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

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

int main(void)
{
	test4();
	return 0;
}

在这里插入图片描述

  
  
  

1.4.3、关于结构体指针的检查说明

  根据上述内容,此处来思考一个问题,如下代码:

void test()
{
	SL s1=NULL;
	SLInit(&s1);
	SLPushBack(&s1, 1);
	SLPrint(&s1);

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

  假设我们将顺序表对应的结构体指针赋值为空,则后续就会出现空指针解引用的操作,是非法的行为。从这我们可以得出,在实现上述接口时,也需要对传入的结构体指针进行检查:

	assert(ps);
	assert(ps!=NULL);

  
  

1.5、顺序表打印、顺序表销毁

1.5.1、顺序表打印:SLPrint

  1)、实现说明

void SLPrint(SL* ps)
{
	assert(ps);//结构体指针检查
	for (int i = 0; i < ps->size; ++i)
	{
		printf("%d ", ps->data[i]);
	}
	printf("\n");
}

  
  

1.5.2、顺序表销毁:SLDestroy

  1)、实现说明

void SLDestory(SL* ps)
{
	assert(ps);//结构体指针检查
	if (ps->data)
	{
		free(ps->data);
		ps->x = NULL;
		ps->size = ps->capacity = 0;
	}
}

  
  
  

1.6、顺序表在pos位置插入、删除

1.6.1、顺序表在pos位置插入:SLInsert

  1)、实现说明
  简介:在pos处插入新数据,即在数组中间位置插入数据,所用方法和头插相似,例如,输入pos=2,则在ps->x[pos]的位置需要插入新输入的数据。

  注意事项:
  1、仍旧需要做扩容检查,此外,还需对输入的pos位置进行检查,即pos需要在数组内部[0,size],pos=0即头插,pos=size即尾插。
  2、在pos位置处插入数据,需要从后往前挪动数据。

void SLInsert(SL* ps, int pos, SLDataType val)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);

	//容量检查
	SLCheckCapacity(ps);

	//数据挪动:从后往前挪
	int end = ps->size;
	while (end > pos)//end-1>=pos 等价于end>=pos+1 可得end>pos
	{
		ps->data[end] = ps->data[end - 1];
		end--;
	}

	//插入数据
	ps->data[pos] = val;
	ps->size++;
}

  
  2)、测试检查

void test5()
{
	SL s1;
	SLInit(&s1);

	SLInsert(&s1, 0, 1);//效果等同头插
	SLPrint(&s1);

	SLInsert(&s1, 1, 2);//效果等同尾插
	SLPrint(&s1);

	SLInsert(&s1, 1, 3);
	SLPrint(&s1);

	SLInsert(&s1, 1, 4);
	SLPrint(&s1);

	SLInsert(&s1, 1, 5);
	SLPrint(&s1);

	SLDestroy(&s1);
}

int main(void)
{
	test5();
	return 0;
}

在这里插入图片描述

  
  
  

1.6.2、顺序表头插、尾插实现3.0

  根据上述实现的SLInsert,我们就可以把之前写的头插、尾插简化:

void SLPushBack(SL* ps, SLDataType val)
{
	SLInsert(ps, ps->size, val);
}
void SLPushFront(SL* ps, SLDataType val)
{
	SLInsert(ps, 0, val);
}

  
  
  

1.6.3、顺序表在pos位置删除:SLErase

  1)、实现说明
   简介:删除pos处的数据,和头删一样使用覆盖法,其余注意事项相同(size下限值,pos范围:[0,size),此时尾部size不能包含进来)。

void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(ps->size);
	assert(pos >= 0 && pos < ps->size);

	int begin = pos + 1;
	while (begin < ps->size)
	{
		ps->data[begin - 1] = ps->data[begin];
		begin++;
	}

	ps->size--;
}

  
  2)、测试检查

void test6()
{
	SL s1;
	SLInit(&s1);
	SLPushFront(&s1, 1);
	SLPushFront(&s1, 2);
	SLPushFront(&s1, 3);
	SLPushFront(&s1, 4);
	SLPushFront(&s1, 5);
	SLPrint(&s1);

	SLErase(&s1, 0);//效果等同于头删
	SLPrint(&s1);

	SLErase(&s1, s1.size-1);//效果等同于尾删
	SLPrint(&s1);

	SLErase(&s1, 1);
	SLPrint(&s1);

	SLErase(&s1, 1);
	SLPrint(&s1);
	
	SLDestroy(&s1);
}


int main(void)
{
	test6();
	return 0;
}

在这里插入图片描述

  
  

1.6.4、顺序表头删、尾删实现3.0

  同理,可使用SLErase对尾删、头删做修改简化:

void SLPopBack(SL* ps)
{
	SLErase(ps, ps->size-1);
}

void SLPopFront(SL* ps)
{
	SLErase(ps, 0);
}

  
  

1.7、顺序表查找、修改

1.7.1、顺序表查找:SLFind

  1)、实现说明
  给定一个值,查找顺序表中是否有该值,若有,则返回对应下标,若无,则返回-1(此处返回的含义是数组下标,数组下标从0开始,故返回-1可表示数组中无该元素)

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

  
  
  

1.7.2、顺序表修改:SLModify

  1)、实现说明
  顺序表修改:给定顺序表中需要修改元素的下标以及修改值。可结合顺序表查找使用,如此就不用特意写该函数:单链表中有演示。

void SLModify(SL* ps, int pos, SLDataType val)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	ps->data[pos] = val;
}

  
  
  
  

2、总体

2.1、Seqlist.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//#define N 100
//typedef int SLDataType;
//typedef struct SeqList
//{
//	SLDataType data[N];
//	size_t size;
//}SL;


typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* data;
	size_t size;
	size_t capacity;
}SL;



void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);

void SLPushBack(SL* ps, SLDataType val);
void SLPushFront(SL* ps, SLDataType val);

void SLPopBack(SL* ps);
void SLPopFront(SL* ps);

void SLInsert(SL* ps, int pos, SLDataType val);
void SLErase(SL* ps, int pos);

int SLFind(SL* ps, SLDataType val);
void SLModify(SL* ps, int pos, SLDataType val);

  
  
  
  

2.2、SList.c

#include"seqlist.h"

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


void SLDestroy(SL* ps)
{
	assert(ps);
	free(ps->data);
	ps->data = NULL;
	ps->capacity = ps->size = 0;
}


void SLPrint(SL* ps)
{
	assert(ps);
	for (int i = 0; i < ps->size; ++i)
	{
		printf("%d ", ps->data[i]);
	}
	printf("\n");
}



void SLPushBack(SL* ps, SLDataType val)
{
	if (ps->capacity == ps->size)//这里一次检查了两种情况:即初始化为NULL时,容量空间已满时;
	{
		size_t newcapacity = (ps->capacity == 0) ? (4) : (ps->capacity * 2);
		SLDataType* tmpdata = (SLDataType*)realloc(ps->data, newcapacity * sizeof(SLDataType));
		if (tmpdata == NULL)//检查
		{
			perror("realloc");
			return 1;
		}
		ps->capacity = newcapacity;
		ps->data = tmpdata;
	}

	ps->data[ps->size] = val;
	ps->size++;
}


void SLPushFront(SL* ps, SLDataType val)
{
	//容量检查
	if (ps->capacity == ps->size)
	{
		size_t newcapacity = (ps->capacity == 0) ? (4) : (ps->capacity * 2);
		SLDataType* tmpdata = (SLDataType*)realloc(ps->data, newcapacity * sizeof(SLDataType));
		if (tmpdata == NULL)//动态申请检查
		{
			perror("realloc");
			return 1;
		}
		ps->capacity = newcapacity;
		ps->data = tmpdata;
	}

	//数据挪动
	int end = ps->size;
	while (end >= 1)
	{
		ps->data[end] = ps->data[end - 1];
		end--;
	}

	//头插
	ps->data[0] = val;
	ps->size++;
}


void SLCheckCapacity(SL* ps)
{
	assert(ps);

	//容量检查
	if (ps->capacity == ps->size)
	{
		size_t newcapacity = (ps->capacity == 0) ? (4) : (ps->capacity * 2);
		SLDataType* tmpdata = (SLDataType*)realloc(ps->data, newcapacity * sizeof(SLDataType));
		if (tmpdata == NULL)//动态申请检查
		{
			perror("realloc");
			return 1;
		}
		ps->capacity = newcapacity;
		ps->data = tmpdata;
	}

}


void SLPushBack(SL* ps, SLDataType val)
{
	assert(ps);

	SLCheckCapacity(ps);
	ps->data[ps->size] = val;
	ps->size++;
}


void SLPushFront(SL* ps, SLDataType val)
{
	assert(ps);

	//容量检查
	SLCheckCapacity(ps);

	//数据挪动
	int end = ps->size;
	while (end >= 1)
	{
		ps->data[end] = ps->data[end - 1];
		end--;
	}

	//头插
	ps->data[0] = val;
	ps->size++;
}



void SLPopBack(SL* ps)
{
	assert(ps!=NULL);
	assert(ps->size > 0);
	ps->size--;
}

void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size > 0);
	//挪动数据
	int begin = 1;
	while(begin < ps->size)
	{
		ps->data[begin-1] = ps->data[begin];
		begin++;
	}
	//数值矫正
	ps->size--;
}







void SLInsert(SL* ps, int pos, SLDataType val)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);

	//容量检查
	SLCheckCapacity(ps);

	//数据挪动:从后往前挪
	int end = ps->size;
	while (end > pos)//end-1>=pos 等价于end>=pos+1 可得end>pos
	{
		ps->data[end] = ps->data[end - 1];
		end--;
	}

	//插入数据
	ps->data[pos] = val;
	ps->size++;
}


void SLPushBack(SL* ps, SLDataType val)
{
	SLInsert(ps, ps->size, val);
}


void SLPushFront(SL* ps, SLDataType val)
{
	SLInsert(ps, 0, val);
}



void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(ps->size);
	assert(pos >= 0 && pos < ps->size);

	int begin = pos + 1;
	while (begin < ps->size)
	{
		ps->data[begin - 1] = ps->data[begin];
		begin++;
	}

	ps->size--;
}


void SLPopBack(SL* ps)
{
	SLErase(ps, ps->size-1);
}

void SLPopFront(SL* ps)
{
	SLErase(ps, 0);
}




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

void SLModify(SL* ps, int pos, SLDataType val)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	ps->data[pos] = val;
}

  
  
  
  

2.3、Test.c

#include"seqlist.h"

void test1()//验证尾插
{
	SL s1;
	SLInit(&s1);
	SLPushBack(&s1, 1);
	SLPushBack(&s1, 2);
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushBack(&s1, 5);
	SLPrint(&s1);
}

void test2()//验证头插
{
	SL s1;
	SLInit(&s1);
	SLPushFront(&s1, 1);
	SLPushFront(&s1, 2);
	SLPushFront(&s1, 3);
	SLPushFront(&s1, 4);
	SLPushFront(&s1, 5);
	SLPrint(&s1);
}

void test3()//验证尾删
{
	SL s1;
	SLInit(&s1);
	SLPushFront(&s1, 1);
	SLPushFront(&s1, 2);
	SLPushFront(&s1, 3);
	SLPushFront(&s1, 4);
	SLPushFront(&s1, 5);
	SLPrint(&s1);

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

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

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

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

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

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

}


void test4()
{
	SL s1;
	SLInit(&s1);
	SLPushFront(&s1, 1);
	SLPushFront(&s1, 2);
	SLPushFront(&s1, 3);
	SLPushFront(&s1, 4);
	SLPushFront(&s1, 5);
	SLPrint(&s1);

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

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

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

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

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

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


void test5()
{
	SL s1;
	SLInit(&s1);

	SLInsert(&s1, 0, 1);//效果等同头插
	SLPrint(&s1);

	SLInsert(&s1, 1, 2);//效果等同尾插
	SLPrint(&s1);

	SLInsert(&s1, 1, 3);
	SLPrint(&s1);

	SLInsert(&s1, 1, 4);
	SLPrint(&s1);

	SLInsert(&s1, 1, 5);
	SLPrint(&s1);

	SLDestroy(&s1);
}


void test6()
{
	SL s1;
	SLInit(&s1);
	SLPushFront(&s1, 1);
	SLPushFront(&s1, 2);
	SLPushFront(&s1, 3);
	SLPushFront(&s1, 4);
	SLPushFront(&s1, 5);
	SLPrint(&s1);

	SLErase(&s1, 0);//效果等同于头删
	SLPrint(&s1);

	SLErase(&s1, s1.size-1);//效果等同于尾删
	SLPrint(&s1);

	SLErase(&s1, 1);
	SLPrint(&s1);

	SLErase(&s1, 1);
	SLPrint(&s1);
}


int main(void)
{
	test6();
	return 0;
}

  
  
  

3、相关练习

3.1、移除元素

  相关链接:题目
  
  

3.2、删除有序数组中的重复项

  相关链接:题目
  
  

3.3、合并两个有序数组

  相关链接:题目
  
  
  
  
  
  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/403745.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络连接的三种模式

文章目录前言一、三种连接模式介绍二、三种网络连接模式的区别前言 在进行虚拟机配置时&#xff0c;网络连接分为三种模式&#xff1a;桥接模式&#xff0c;NAT模式&#xff0c;主机模式 一、三种连接模式介绍 张三、李四、王五在同一个网段&#xff0c;所以他们之间可以相互…

数据结构---双链表

专栏&#xff1a;数据结构 个人主页&#xff1a;HaiFan. 专栏简介&#xff1a;从零开始&#xff0c;数据结构&#xff01;&#xff01; 双链表前言双链表各接口的实现为要插入的值开辟一块空间BuyLN初始化LNInit和销毁LNDestory打印链表中的值LNPrint尾插LNPushBack和尾删LNPop…

vue2+elementUI完成添加学生删除学生案列

效果图&#xff1a; 点击添加学生按钮&#xff0c;弹出Dialog,收集用户信息&#xff1a; el-table中自定义复选框&#xff0c;选中一行&#xff0c;可以点击删除 代码区域&#xff1a;就一个HTML文件 <!DOCTYPE html> <html lang"en"> <head>&…

Flume基操

Flume概述 Flume 定义 Flume 是 Cloudera 提供的一个高可用的&#xff0c;高可靠的&#xff0c;分布式的海量日志采集、聚合和传输的系统。Flume 基于流式架构&#xff0c;灵活简单。 Flume最主要的作用就是&#xff0c;实时读取服务器本地磁盘的数据&#xff0c;将数据写入到…

带恒温冷藏功能的便携式自动采样器——可用于毒情监测

污水采样在验毒的工作流程中是怎样进行的呢&#xff1f; 污水采样&#xff1a;每个季度采样一次。例如在某市48家污水处理厂54个进水口采取水样&#xff0c;用便携式水质自动采样器连续采样7天&#xff0c;一天采样12次成为一个混合样。也就是说&#xff0c;一次采样的话&…

如何在 VS Code 中安装运行、编写C语言程序

1.下载 安装VS Code 去官网下载&#xff1a;https://code.visualstudio.com/Download 直接下载&#xff0c;安装即可。 2.安装VS code中2个插件 打开软件运行&#xff0c;在扩展商店中分别搜索安装 C/C 和 code runner 插件 3.下载mingb64 官网下载 https://sourceforge…

消息队列MQ用来做什么的,市场上主流的四大MQ如何选择?RabbitMQ带你HelloWorld!

文章目录MQ用来做什么的MQ会有什么样的麻烦MQ消息队列模式分类MQ消息队列常用协议市场主流四大MQRabbitMQ项目开发RabbitMQ中的组成部分MQ用来做什么的 省流 &#xff1a;系统解耦、异步调用、流量削峰 系统解耦 首先举例下面这个场景&#xff0c;现有ABCDE五个系统&#xff…

小黑子—Java从入门到入土过程:第二章

Java零基础入门2.0Java系列第二章1. 注释和关键字2. 字面量3. 变量3.1 基本用法3.2 使用方式3.3 注意事项4. 变量练习5. 计算机中的数据存储5.1 计算机的存储规则5.2 进制5.3 进制间转换二进制转十八进制转十十六进制转十十进制转其他进制6. 数据类型7. 定义变量的练习8. 标识符…

MATLAB——将直接型转化为并联型和级联型

题目1(IIR)&#xff1a; 已知一个系统的传递函数为&#xff1a; H&#xff08;z&#xff09;8−4z−111z−2−2z−31−1.25z−10.75z−2−0.125z−3H&#xff08;z&#xff09;\frac{8-4z^{-1}11z^{-2}-2z^{-3}}{1-1.25z^{-1}0.75z^{-2}-0.125z^{-3}}H&#xff08;z&#xff09…

Leedcode 1137. 第 N 个泰波那契数

泰波那契序列 Tn 定义如下&#xff1a; T0 0, T1 1, T2 1, 且在 n > 0 的条件下 Tn3 Tn Tn1 Tn2 给你整数 n&#xff0c;请返回第 n 个泰波那契数 Tn 的值。 示例 1&#xff1a; 输入&#xff1a;n 4 输出&#xff1a;4 解释&#xff1a; T_3 0 1 1 2 T_4 1 …

2.线性表的顺序表示

数据结构很重要&#xff01; 数据结构很重要&#xff01;&#xff01;&#xff01; 数据结构很重要&#xff01;&#xff01;&#xff01;&#xff01; 思考 1.线性表的顺序表示内容有哪些&#xff1f;&#xff08;What&#xff09; 2.为什么要学线性表的顺序表示? ? (Why)…

POI 操作Excel的单元格样式超过64000的异常问题解决

文章目录POI 操作Excel的单元格样式超过64000的异常问题解决问题描述问题原因问题分析和解决简单的Excel文件生成Demo最终的解决方案POI 操作Excel的单元格样式超过64000的异常问题解决 问题描述 在用POI 生成Excel文件时&#xff0c;如果自定义的单元格的样式超过64000行&am…

SpringBoot+WebSocket实时监控异常

# 写在前面此异常非彼异常&#xff0c;标题所说的异常是业务上的异常。最近做了一个需求&#xff0c;消防的设备巡检&#xff0c;如果巡检发现异常&#xff0c;通过手机端提交&#xff0c;后台的实时监控页面实时获取到该设备的信息及位置&#xff0c;然后安排员工去处理。因为…

2.9.1 Packet Tracer - Basic Switch and End Device Configuration(作业)

Packet Tracer - 交换机和终端设备的基本 配置地址分配表目标使用命令行界面 (CLI)&#xff0c;在两台思科互联网络 操作系统 (IOS) 交换机上配置主机名和 IP 地址。使用思科 IOS 命令指定或限制对设备 配置的访问。使用 IOS 命令来保存当前的运行配置。配置两台主机设备的 IP …

JavaScript Boolean(布尔)对象

Boolean&#xff08;布尔&#xff09;对象用于将非布尔值转换为布尔值&#xff08;true 或者 false&#xff09;&#xff0c;是三种包装对象&#xff1a;Number、String和Boolean中最简单的一种&#xff0c;它没有大量的实例属性和方法。在线实例检查布尔值检查布尔对象是 true…

大数据-玩转数据-mysql规范

整体图谱 正文部分 一、数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字&#xff08;如果表名中包含关键字查询时&#xff0c;需要将其用单引号括起来&#xff09; 数据库对象的命名要能做到见名识意&#xff…

【算法时间复杂度】学习记录

最近开算法课&#xff0c;开几篇文章记录一下算法的学习过程。 关于算法的重要性 学习计算机当程序员的话&#xff0c;在编程过程中是绕不开算法这个大矿山的&#xff0c;需要我们慢慢挖掘宝藏。 算法&#xff08;Algorithm&#xff09;是指用来操作数据、解决程序问题的一组…

信创和去O大潮下,Oracle OCP(1z0-082 1z0-083)的含金量有多少?(文末附录像)

我自己就考了挺多Oracle的认证&#xff0c;下面是从Oracle的certview网站&#xff08;网址是certview加上点oracle点com&#xff09;上面查询到的姚远老师自己的Oracle证书。 目前国内强调自主可控&#xff0c;推信创和去Oracle数据库&#xff0c;很多想考Oracle OCP认证的学员…

Spring框架源码分析一

如何看源码&#xff08;方法论&#xff09;不要忽略源码中的注释使用翻译工具先梳理脉络&#xff0c;然后梳理细节即总分总&#xff0c;先总体过一遍&#xff0c;再看细节&#xff0c;再做一个总结大胆猜测&#xff08;8分靠猜&#xff09;&#xff0c;小心验证&#xff0c;再调…

ChatGPT真神奇,但是也真焦虑

ChatGPT火爆ChatGPT的火爆程度不用说也知道。就目前来说&#xff0c;已经开始冲击各行业了&#xff0c;比如客服、智能助手、语言学习、自然语言处理等等等。。ChatGPT冲击冲击最高的可能就是中间这个段位的了。高段位无法取代&#xff0c;但是低段位&#xff0c;通过使用ChatG…