数据结构之动态开辟顺序表

**

1.定义一个动态顺序表

由于定长开辟顺序表的大小依赖于存储空间的初始分配量 SIZE,要想解决此问题,需要在顺序表存储空间不足时进行动态扩容
**

#define INIT_SIZE 10  // 存储空间的初始分配量
typedef struct Dsqlist
{ 
	int *elem;     // 数组存储数据元素,需在初始化时动态开辟内存
	int usedsize;  // 顺序表的当前长度
	int size;      // 顺序表存储空间的大小
}Dsqlist,*PDSqlist;

2.动态顺序表的各种操作

void InitList(PDSqlist psq);
bool Insert(PDSqlist psq,int pos,int val);
int Search(PDSqlist Psq,int pos,int key);//查找 key 值
bool DeletePos(PDSqlist Psq,int pos,int *rtv);//删除 pos 位置的值
bool Delete(PDSqlist Psq,int pos,int key);//删除一个 key 值
void Clear(PDSqlist psq);
void Destroy(PDSqlist psq);
void Show(PDSqlist psq)

①初始化
顺序表的初始化就是把顺序表初始化为空的顺序表,需为数组elem动态开辟存储空间,并把顺序表的长度usedsize置为0,size置为初始分配量INIT_SIZ即可

  void InitList(PDSqlist psq)
    {
    	assert(psq != NULL);
    	psq->elem = (int *)malloc(sizeof(int) * INIT_SIZE);
    	assert(psq->elem != NULL);//判断是否开辟成功
    	psq->usedsize = 0;
    	psq->size = INIT_SIZE;
    }

②判断顺序表是否为满

static bool isFull(PDSqlist psq)
{
	if (psq->usedsize == psq->size)
	{
		return true;
	}
	return false;
}

③为顺序表动态扩容
当顺序表为满时,需要调用动态扩容函数对顺序表的elem数组进行动态扩容,这里采用二倍扩容的方式

static void Inc(PDSqlist psq)
{
	int *p = (int *)realloc(psq->elem, psq->size*sizeof(int) * 2);
	if (p != NULL)
	{
		psq->elem = p;
	}
	psq->size *= 2;
}

4、在 pos 位置插入 val 值
与之前的 Insert()函数 不同的是,当顺序表为满时,需要调用动态扩容函数对顺序表的elem数组进行动态扩容

bool Insert(PDSqlist psq, int pos, int val)
{
	if (isFull(psq))
	{
		Inc(psq);
	}
	for (int i = psq->usedsize - 1; i >= pos; i--)
	{
		psq->elem[i + 1] = psq->elem[i];
	}
	psq->elem[pos] = val;
	psq->usedsize++;
	return true;
}

5、释放动态开辟的存储空间
由于elem数组是动态开辟的,因此具有动态扩容顺序表与普通顺序表不同的是需要专门设立一个函数对动态开辟的存储空间进行释放,否则会在程序运行过程中产生内存泄露。

void Destroy(PDSqlist psq)
{
	free(psq->elem);
	psq->elem = NULL;
	psq->usedsize = 0;
	psq->size = 0;
}

以下操作和定长开辟顺序表完全一致

static bool isEmpty(PDSqlist Psq)//判断是否为空
{
	return Psq->usedsize == 0;
}
int Search(PDSqlist Psq,int pos,int key)//查找 key 值
{
	if(pos < 0 || pos >= Psq->usedsize || isEmpty(Psq))
	{
		return -1;
	}
	for(int i = pos;i < Psq->usedsize;i++)
	{
		if(Psq->elem[i] == key)
		{
			return i;
		}
	}
	return -1;
}

bool DeletePos(PDSqlist Psq,int pos,int *rtv)//删除 pos 位置的值
{
	if(pos < 0 || pos >= Psq->usedsize || isEmpty(Psq))
	{
		return false;
	}
	if(rtv != NULL)
	{
		*rtv = Psq->elem[pos];
	}
	for(int i = pos;i < Psq->usedsize-1;i++)
	{
		Psq->elem[i] = Psq->elem[i+1];
	}
	Psq->usedsize--;
	return true;
}

bool Delete(PDSqlist Psq,int pos,int key)//删除一个 key 值
{
	int index = Search(Psq,pos,key);
	if(index == -1)
	{
		return false;
	}
	return DeletePos(Psq,index,NULL);
}

void Clear(PDSqlist psq)//清空
{
	psq->usedsize = 0;
	//psq->size = 0;
}


void Show(PDSqlist psq)
{
	for (int i = 0; i < psq->usedsize; i++)
	{
		printf("%d ",psq->elem[i]);
	}
	printf("\n");
}

dsqlist.h:

#pragma once
#define INIT_SIZE 10
typedef struct Dsqlist
{
	int *elem;
	int usedsize;
	int size;
}Dsqlist,*PDSqlist; 
 
void InitList(PDSqlist Psq);
 
bool Insert(PDSqlist Psq,int pos,int val);
 
int Search(PDSqlist Psq,int pos,int key);
 
bool DeletePos(PDSqlist Psq,int pos,int *rtv);
 
bool Delete(PDSqlist Psq,int pos,int key);
 
bool GetElem(PDSqlist Psq,int pos,int *rtv); 
 
int GetLength(PDSqlist Psq);
 
void Clear(PDSqlist Psq);
 
void Destroy(PDSqlist Psq);
 
void Show(PDSqlist Psq);

dsqlist.cpp:

#include "dsqlist.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
 
void InitList(PDSqlist Psq)
{
	assert(Psq != NULL);
	Psq->elem = (int *)malloc(INIT_SIZE * sizeof(int));
	assert(Psq->elem != NULL);
	Psq->usedsize = 0;
	Psq->size = INIT_SIZE;
}
 
 
static void Inc(PDSqlist Psq)
{
	int *p = (int *)realloc(Psq->elem,Psq->size *2 *sizeof(int));
	assert(p != NULL);
	if (p != NULL)
	{
		Psq->elem = p;
	}
	assert(Psq->elem != NULL);
	Psq->size *= 2;
}
 
static bool IsFull(PDSqlist Psq)
{
	return Psq->usedsize == Psq->size;
}
 
 
bool Insert(PDSqlist Psq,int pos,int val)
{
	assert(Psq != NULL);
	if (pos < 0 || pos > Psq->usedsize)
	{
		return false;
	}
	if (IsFull(Psq))
	{
		Inc(Psq);
	}
	for (int i = Psq->usedsize-1; i >= pos; i--)
	{
		Psq->elem[i+1] = Psq->elem[i];
	}
	Psq->elem[pos] = val;
	Psq->usedsize++;
	return true;
}
 
static bool IsEmpty(PDSqlist Psq)
{
	return Psq->usedsize == 0;
}
 
int Search(PDSqlist Psq,int pos,int key)
{
	assert(Psq != NULL);
	if (pos < 0 || pos > Psq->usedsize || IsEmpty(Psq))
	{
		return -1;
	}
	for (int i = pos; i < Psq->usedsize; i++)
	{
		if (Psq->elem[i] == key)
		{
			return i;
		}
	}
	return -1;
 
}
 
bool DeletePos(PDSqlist Psq,int pos,int *rtv)
{
	assert(Psq != NULL);
	if (pos < 0 || pos >= Psq->usedsize || IsEmpty(Psq))
	{
		return false;
	}
	if (rtv != NULL)
	{
		*rtv = Psq->elem[pos];
	}
	for (int i = pos; i < Psq->usedsize; i++)
	{
		Psq->elem[i] = Psq->elem[i+1];
	}
	Psq->usedsize--;
	return true;
 
}
 
bool Delete(PDSqlist Psq,int pos,int key)
{
	assert(Psq != NULL);
	int index = Search(Psq,pos,key);
	if (index == -1)
	{
		return false;
	}
	return DeletePos(Psq,index,NULL);
}
 
bool GetElem(PDSqlist Psq,int pos,int *rtv)
{
	assert(Psq != NULL);
	*rtv = Psq->elem[pos];
	return true;
}
 
int GetLength(PDSqlist Psq)
{
	assert(Psq !=NULL);
	return Psq->usedsize;
}
 
void Clear(PDSqlist Psq)
{
	assert(Psq != NULL);
	Psq->usedsize = 0;
}
 
void Destroy(PDSqlist Psq)
{
	assert(Psq != NULL);
	free(Psq->elem);
	Psq->elem = NULL;
	Psq->size = 0;
	Psq->usedsize = 0;
}
 
void Show(PDSqlist Psq)
{
	assert(Psq !=NULL);
	for (int i = 0; i < Psq->usedsize; i++)
	{
		printf("%d ",Psq->elem[i]);
	}
	printf("\n");
}

test.cpp

#include<stdio.h>
#include<vld.h>
#include "dsqlist.h"
int main()
{
	Dsqlist ds;
	InitList(&ds);
	for (int i = 0; i < 70; i++)
	{
		Insert(&ds,i,i);
	}
	Show(&ds);
	Delete(&ds,0,2);
	Delete(&ds,0,9);
	Delete(&ds,0,0);
	Show(&ds);
	Destroy(&ds);
	return 0;
}
### 如何用数据结构实现动态顺序表 动态顺序表是一种基于线性表的数据结构,其核心在于通过动态内存分配技术来扩展存储空间。以下是其实现的关键部分以及具体方法: #### 1. 定义动态顺序表的结构体 为了支持动态扩容和灵活的操作,通常会定义一个类似于以下形式的结构体[^1]: ```c typedef int SLDataType; typedef struct SeqList { SLDataType* array; // 指向动态开辟的数组的指针 size_t size; // 当前有效数据个数 size_t capacity; // 总的空间容量大小 } SeqList; ``` 该结构体包含了三个主要成员变量: - `array` 是指向实际存储区域的指针。 - `size` 表示当前已使用的元素数量。 - `capacity` 则表示整个动态顺序表的最大容量。 #### 2. 初始化动态顺序表 初始化函数负责创建一个新的动态顺序表实例并为其分配初始内存资源。一般情况下可以选择较小的默认值作为起始容量,并允许后续按需增长[^4]: ```c void InitSeqList(SeqList* ps) { ps->array = (SLDataType*)malloc(sizeof(SLDataType) * INIT_CAPACITY); // 假设INIT_CAPACITY=10 if (!ps->array) exit(-1); ps->size = 0; ps->capacity = INIT_CAPACITY; } ``` 这里需要注意的是错误处理机制;如果无法成功申请到足够的内存,则程序应采取适当措施终止运行或者报告异常情况给调用者知道。 #### 3. 插入新元素至末尾位置 当需要新增加一条记录时,先判断现有空间是否足够容纳下一个项目。如果不充足的话就执行一次重新分配过程以增加额外可用面积后再继续正常流程[^3]: ```c bool InsertToTail(SeqList* ps, SLDataType x){ if(ps->size >= ps->capacity){ ResizeArray(ps); // 如果满了则调整大小 } ps->array[ps->size++] = x; // 将新的元素加入列表最后面的位置上 return true; } // 扩展数组的方法 static void ResizeArray(SeqList* ps){ const size_t newCapacity = ps->capacity + INCREMENT_STEP; // 新增步长增量INCREAMENT_STEP可自定 SLDataType* newArrayPtr = realloc(ps->array,sizeof(SLDataType)*newCapacity); if(newArrayPtr != NULL){ ps->array=newArrayPtr ; ps->capacity=newCapacity ; }else{ printf("Memory allocation failed!\n"); } } ``` 上述代码片段展示了如何安全有效地完成插入动作的同时也考虑到了边界条件下的特殊情形处置策略。 #### 4. 删除指定索引处的节点 删除某个特定下标的对象涉及到两个方面的工作:一是逻辑上的剔除标记更改;二是物理层面可能引发的一系列连锁反应比如紧缩剩余单元格间距等操作: ```c bool RemoveByIndex(SeqList* ps,size_t index){ if(index>=ps->size ||index<0)return false;//越界检测 for(int i=index;i<(int)(ps->size)-1;i++){ ps->array[i]=ps->array[i+1]; // 移动后面的每一个向前填补空缺位子 } --(ps->size); // 更新计数值减少一位 return true; } ``` 此段落描述了一个标准做法即逐一遍历受影响区间内的所有条目并将它们逐一迁移直至目标被完全覆盖掉为止。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值