初识顺序表

        大家好久不见!今天我们就来认识一下顺序表。

顺序表

目录

顺序表

创建顺序表 

 头插,尾插

 头删,尾删

 任意下标位置插入和删除

 查找

 完整代码

Sepqen.h 

Sepqen.c 

 test.c

小结 


创建顺序表 

        顺序表与数组类似,但与数组不同的是,顺序表需要连续有效的数据。要创建顺序表,那么首先创建结构体来存其数据。代码如下:

typedef struct Seqlist
{
	SLDataType* a;
	int size;//有效数据
	int capacity;//容量
}SL;

         值得注意的是,在开辟容量时我们一般选择2倍进行创建,由于2的倍数会爆炸式增长,于是扩容的次数便会减少。

        接下来就是编写初始化顺序表和将开辟的空间销毁的函数,在编写销毁函数时需要注意,若顺序表本就为空,那就不需要进行销毁,需要进行判断。为了防止传入空指针,还需要进行断言确认一下。代码如下:

//初始化
void SLInit(SL* ps1)
{
    assert(ps1);
	ps1->a = NULL;
	ps1->size = 0;
	ps1->capacity = 0;
}

//销毁
void SLDestory(SL* ps1)
{
    assert(ps1);
	if (ps1->a != NULL)
	{
		free(ps1->a);
		ps1->a = NULL;
	}
	ps1->size = 0;
	ps1->capacity = 0;
}

        那么顺序表有什么功能呢,首要的功能便是头插头删和尾插尾删,即在头部插入数据和删除数据以及在尾部插入数据和删除数据,我们先将其声明,然后对其进行编写。

 头插,尾插

        我们首先来进行最简单的尾插。

        在进行尾插之前,应该首先考虑空间是否足够大,需要进行判断,如果空间容量不够,需要增容。若使用realloc进行开辟则需要对返回值进行判断,最后更新地址。

        接着对尾插函数进行编写,在空间足够的情况下,就可以直接对尾部进行插入,把想要插入的值直接赋值给尾部位置,插入完成后就对尾部位置进行更新。代码如下:

void SLPushBack(SL* ps1, SLDataType x)
{
    assert(ps1);
	    if (ps1->size == ps1->capacity)
	{
		int newCapacity = ps1->capacity == 0 ? 4 : ps1->capacity * 2;
		SLDataType* tmp = realloc(ps1->a, sizeof(SLDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps1->a = tmp;
	}
	ps1->a[ps1->size] = x;
	ps1->size++;
}

         接下来就是头插,头插和尾插类似,而且也需要对容量进行判断。那就直接将容量判断封装成函数CheckCapacity,代码如下:

//检查容量
void CheckCapacity(SL* ps1)
{
    assert(ps1);
	if (ps1->size == ps1->capacity)
	{
		int newCapacity = ps1->capacity == 0 ? 4 : ps1->capacity * 2;
		SLDataType* tmp = realloc(ps1->a, sizeof(SLDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps1->a = tmp;
	}
}

        头插的思路也很简单,既然是顺序表,那么就只能把数据向后挪。也就是说,需要一个一个的进行换位。

        最后将想要插入的数据对位置进行赋值,更新size。代码如下:

void SLPushFront(SL* ps1, SLDataType x)
{
    assert(ps1);
	CheckCapacity(ps1);
	int end = ps1->size - 1;
	while (end >= 0)
	{
		ps1->a[end + 1] = ps1->a[end];
		end--;
	}

	ps1->a[0] = x;
	ps1->size++;
}

 头删,尾删

        首先来编写尾删,尾删直接将size--即可,无需多此一举。有效数据都在size之前,空间会被重复利用。当然,当顺序表空了的时候就不能删了,需要进行判断。代码如下:

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

        之后就是头删,既然想要把最前面的数据删除,那么就可以让后面的数据直接向前覆盖,位置处于size时停止覆盖,最后将size--。代码如下:

        

void SLPopFront(SL* ps1)
{
    assert(ps1);
	assert(ps1->size > 0);
	int begin = 1;
	while (begin < ps1->size)
	{
		ps1->a[begin - 1] = ps1->a[begin];
		begin++;
	}
	ps1->size--;
}

 任意下标位置插入和删除

        接下来就是编写随机插入和删除的函数了,当然只能在顺序表的范围内插入和删除。所以传入的位置必须得进行判断。 

        编写插入之前,首先得检查容量是否足够,不足的话则进行增容。接着就是对函数的编写。在一个位置进行插入,那么直接把该位置以及后面的元素向后挪动,再把这个位置进行覆盖就可以了。注意,也可以在头部和尾部插入哦!当然别忘了size++。代码如下:

void SLInsert(SL* ps1, int pos, SLDataType x)
{
	assert(ps1);
	assert(pos >= 0 && pos <= ps1->size);
	CheckCapacity(ps1);
	//挪动数据
	int end = ps1->size - 1;
	while (end >= pos)
	{
		ps1->a[end + 1] = ps1->a[end];
		end--;
	}
	ps1->a[pos] = x;
	ps1->size++;
}

        之后就是对任意位置的删除了,思路没什么变化,就是向前进行覆盖。然后size--即可。代码如下:

void SLErase(SL* ps1, int pos)
{
	assert(ps1);
	assert(pos >= 0 && pos < ps1->size);
	//挪动覆盖
	int begin = pos + 1;
	while (begin < ps1->size)
	{
		ps1->a[begin - 1] = ps1->a[begin];
		begin++;
	}
	ps1->size--;
}

 查找

        最后一个便是查找位置,找到之后返回下标,没有找到返回-1即可。

        那么如何查找位置?其实很简单,用for循环进行遍历就可以了。遍历到查找的值时,返回下标。 代码如下:

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

 完整代码

Sepqen.h 

#pragma once

#include
#include
#include
typedef int SLDataType;//这里将int重命名的意义在于:可以方便改变变量的类型。

typedef struct Seqlist
{
	SLDataType* a;
	int size;//有效数据
	int capacity;//容量
}SL;

//初始化
void SLInit(SL* ps);

//销毁
void SLDestory(SL* ps);

//打印检验
void SLPrint(SL* ps);

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

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

//尾插
void SLPushBack(SL* ps, SLDataType x);

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

//下标位置插入
void SLInsert(SL* ps, int pos, SLDataType x);

//下标位置删除
void SLErase(SL* ps, int pos);

//查找位置,返回下标
int SLFind(SL* ps, SLDataType x);

Sepqen.c 

#include"Sepqen.h"

//初始化
void SLInit(SL* ps1)
{
	assert(ps1);
	ps1->a = NULL;
	ps1->size = 0;
	ps1->capacity = 0;
}

//销毁
void SLDestory(SL* ps1)
{
	assert(ps1);
	if (ps1->a != NULL)
	{
		free(ps1->a);
		ps1->a = NULL;
	}
	ps1->size = 0;
	ps1->capacity = 0;
}

//打印检验
void SLPrint(SL* ps1)
{
	assert(ps1);
	for (int i = 0; i < ps1->size; i++)
	{
		printf("%d ", ps1->a[i]);
	}
	printf("\n");
}

//检查容量
void CheckCapacity(SL* ps1)
{
	assert(ps1);
	if (ps1->size == ps1->capacity)
	{
		int newCapacity = ps1->capacity == 0 ? 4 : ps1->capacity * 2;
		SLDataType* tmp = realloc(ps1->a, sizeof(SLDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps1->a = tmp;
	}
}

//尾插
void SLPushBack(SL* ps1, SLDataType x)
{
	assert(ps1);
	CheckCapacity(ps1);
	ps1->a[ps1->size] = x;
	ps1->size++;
}

//头插
void SLPushFront(SL* ps1, SLDataType x)
{
	assert(ps1);
	CheckCapacity(ps1);
	int end = ps1->size - 1;
	while (end >= 0)
	{
		ps1->a[end + 1] = ps1->a[end];
		end--;
	}

	ps1->a[0] = x;
	ps1->size++;
}

//尾删
void SLPopBack(SL* ps1)
{
	assert(ps1);
	assert(ps1->size > 0);
	ps1->size--;
}

//头删
void SLPopFront(SL* ps1)
{
	assert(ps1);
	assert(ps1->size > 0);
	int begin = 1;
	while (begin < ps1->size)
	{
		ps1->a[begin - 1] = ps1->a[begin];
		begin++;
	}
	ps1->size--;
}

//下标位置插入
void SLInsert(SL* ps1, int pos, SLDataType x)
{
	assert(ps1);
	assert(pos >= 0 && pos <= ps1->size);
	CheckCapacity(ps1);
	//挪动数据
	int end = ps1->size - 1;
	while (end >= pos)
	{
		ps1->a[end + 1] = ps1->a[end];
		end--;
	}
	ps1->a[pos] = x;
	ps1->size++;
}

void SLErase(SL* ps1, int pos)
{
	assert(ps1);
	assert(pos >= 0 && pos < ps1->size);
	//挪动覆盖
	int begin = pos + 1;
	while (begin < ps1->size)
	{
		ps1->a[begin - 1] = ps1->a[begin];
		begin++;
	}
	ps1->size--;
}

//查找位置,返回下标
int SLFind(SL* ps1, SLDataType x)
{
	assert(ps1);
	for (int i = 0; i < ps1->size; i++)
	{
		if (ps1->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}

 test.c

#include"Sepqen.h"

void TestSL1()
{
	SL s1;
	SLInit(&s1);
    //进行测试
	SLDestory(&s1);
}


int main()
{
	TestSL1();

	return 0;
}

小结 

         对顺序表的认识到这里就结束啦,大家来年都要继续加油哦!我们下次见!

你可能感兴趣的:(数据结构,c语言)