顺序表与链表

顺序表

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

顺序表一般可以分为:

  1. 静态顺序表:使用定长数组存储
#define N 100
typedef int SLDataType;
typedef struct Seqlist
{
   SLDataType* a[N];  //定长数组
   size_t size;  // 有效数据的个数
}SeqList;
  1. 动态顺序表:使用动态开辟的数组存储
typedef int SLDataType; //定义数据类型方便更改
typedef struct SeqList
{
	SLDataType* a;   //指向动态开辟的数组
	size_t size;     //有效数据个数
	size_t capacity;    //容量大小
}SeqList;

动态顺序表增删查改等实现:
https://github.com/Ellyn-jia/Data-structure/tree/master/SeqList/SeqList

动态顺序表的初始化与销毁

void SeqListInit(SeqList* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}
void SeqListDestory(SeqList* ps)
{
	assert(ps);
	free(ps);
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

动态顺序表的增容

//增容
void SeqListCheck(SeqList* ps)
{
	if (ps->size == ps->capacity)
	{
		size_t newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		ps->a = (SLDataType *)realloc(ps->a, newcapacity * sizeof(SLDataType));
		ps->capacity = newcapacity;
	}
}

动态顺序表的头插与尾插

//尾插
void SeqListPushBack(SeqList* ps, SLDataType x)
{
	assert(ps);
	SeqListCheck(ps);
	ps->a[ps->size] = x;
	ps->size++;
}
//头插
void SeqListPushFront(SeqList* ps, SLDataType x)
{
	assert(ps);
	SeqListCheck(ps);
	size_t end = ps->size;
	while (end)
	{
		ps->a[end] = ps->a[end - 1];
		end--;
	}
	ps->a[0] = x;
	ps->size++;
}

动态顺序表的头删与尾删

//头删
void SeqListPopFront(SeqList* ps)
{
	assert(ps);
	size_t start = 0;
	while (start < ps->size - 1)
	{
		ps->a[start] = ps->a[start + 1];
		start++;
	}
	ps->size--;
}
//尾删
void SeqListPopBack(SeqList* ps)
{
	assert(ps);
	ps->size--;
}

动态顺序表在某一位置的插入与删除

//在pos位置插入
void SeqListInsert(SeqList* ps, size_t pos, SLDataType x)
{
	assert(ps);
	assert(pos <= ps->size);
	SeqListCheck(ps);//若容量不够则增容

	size_t end = ps->size;
	while (end > pos)
	{
		ps->a[end] = ps->a[end - 1];
	}
	ps->a[pos] = x;
	ps->size++;
}
//删除
void SeqListErase(SeqList* ps, size_t pos)
{
	assert(ps);
	assert(pos <= ps->size);

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

在动态顺序表中查找某一值

//在动态顺序表中查找某一值
//若找到则返回所在位置的下标,若无则返回-1
int SeqListFind(SeqList* ps, SLDataType x)
{
	for (size_t i = 0; i < ps->size; i++)
	{
		if (ps->a[i] == x)
			return i;
	}
	return -1;
}
链表

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

链表的结构是多样的:

  1. 单向、双向
    在这里插入图片描述在这里插入图片描述
  2. 带头指针、不带头指针
    在这里插入图片描述
    在这里插入图片描述
  3. 单链表、循环单链表
    在这里插入图片描述
    在这里插入图片描述

常见的两种链表结构:

  1. 无头指针单向不循环链表:结构简单,在考察中出现较多
    实现:https://github.com/Ellyn-jia/Data-structure/tree/master/SList/SList
typedef int SLDataType;
typedef struct SListNode{
	SLDataType data;
	struct SListNode* next;
}SListNode;

  1. 带头双向循环链表:结构复杂,但是多在实际中使用,使用简单。
    实现:https://github.com/Ellyn-jia/Data-structure/tree/master/DList/DList
typedef int LTDataType;
typedef struct ListNode{
	LTDataType data;
	struct ListNode* prev;
	struct ListNode* next;
}ListNode

1、无头单向不循环链表的增删查改


//尾插
void SListPushBack(SListNode** pplist, SLDataType x)
{
	SListNode* newNode = BuySListNode(x);
	if (*pplist == NULL)
		*pplist = newNode;
	else
	{
		SListNode* tail = *pplist;
		while (tail->next != NULL)
			tail = tail->next;
		tail->next = newNode;
	}
}
//头插
void SListPushFront(SListNode** pplist, SLDataType x)
{
	SListNode* newNode = BuySListNode(x);
	newNode->next = *pplist;
	*pplist = newNode;
}
//尾删
void SListPopBack(SListNode** pplist)
{
	if (*pplist == NULL)
		return;
	else if ((*pplist)->next == NULL)
	{
		free(*pplist);
		*pplist = NULL;
	}
	else
	{
		SListNode* tail = *pplist;
		SListNode* prev = NULL;
		while (tail->next != NULL)
		{
			prev = tail;
			tail = tail->next;
		}
		prev->next = NULL;
		free(tail);
	}
}
//头删
void SListPopFront(SListNode** pplist)
{
	if (*pplist == NULL)
		return;
	else
	{
		SListNode* head = *pplist;
		*pplist = (*pplist)->next;
		free(head);
	}
}



//链表在pos位置后的插入与删除
void SListInsertAfter(SListNode* pos, SLDataType x)
{
	SListNode* newNode = BuySListNode(x);
	SListNode* next = pos->next;
	pos->next = newNode;
	newNode->next = next;
}
void SListEraseAfter(SListNode* pos)
{
	SListNode* next = pos->next;
	if (next)
	{
		pos->next = next->next;
		free(next);
	}
}


//查找链表中某一值的位置
SListNode* SListFind(SListNode* plist, SLDataType x)
{
	SListNode* cur = plist;
	while (cur)
	{
		if (cur->data == x)
			return cur;
		else
			cur = cur->next;
	}
	return NULL;
}


//创建新的结点
SListNode* BuySListNode(SLDataType x)
{
	SListNode* newNode = (SListNode*)malloc(sizeof(SListNode));
	newNode->data = x;
	newNode->next = NULL;
	return newNode;
}

//链表的销毁
void SListDestory(SListNode** pplist)
{
	SListNode* cur = *pplist;
	while (cur)
	{
		SListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pplist = NULL;
}

2、带头双向循环链表的增删查改


//创建新的结点,prev指针指向前一个结点,next指针指向下一个结点
ListNode* BuyNode(LTDataType x)
{
	ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
	newNode->data = x;
	newNode->next = NULL;
	newNode->prev = NULL;
	return newNode;
}


//创建一个链表时,只有头指针
//头指针的prev与next 都指向自己
ListNode* ListCreat()
{
	ListNode* head = (ListNode*)malloc(sizeof(ListNode));
	head->next = head;
	head->prev = head;
	return head;
}

//链表的销毁
void ListDestory(ListNode* phead)
{
	ListNode* cur = phead->next;
	while (cur != phead)
	{
		ListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	free(phead);
}


//链表尾插
void ListPushBack(ListNode* phead, LTDataType x)
{
	ListNode* newNode = BuyNode(x);
	ListNode* prev = phead->prev;
	phead->prev = newNode;
	newNode->next = phead;
	newNode->prev = prev;
	prev->next = newNode;
}
//链表头插
void ListPushFront(ListNode* phead, LTDataType x)
{
	ListNode* newNode = BuyNode(x);
	ListNode* first = phead->next;
	phead->next = newNode;
	newNode->prev = phead;
	first->prev = newNode;
	newNode->next = first;
}
//链表尾删
void ListPopBack(ListNode* phead)
{
	ListNode* tail = phead->prev;
	phead->prev = tail->prev;
	tail->prev->next = phead;
	free(tail);
}
//链表头删
void ListPopFront(ListNode* phead)
{
	ListNode* first = phead->next;
	ListNode* second = first->next;
	phead->next = first->next;
	second->prev = phead;
	free(first);
}


//在链表中pos位置的插入与删除
void ListInsert(ListNode* pos, LTDataType x)
{
	ListNode* prev = pos->prev;
	ListNode* newNode = BuyNode(x);
	prev->next = newNode;
	newNode->prev = prev;
	pos->prev = newNode;
	newNode->next = pos;
}
void ListErase(ListNode* pos)
{
	ListNode* prev = pos->prev;
	prev->next = pos->next;
	pos->next->prev = prev;
	free(pos);
}


//在链表中查找某一值的位置
ListNode* ListFind(ListNode* phead, LTDataType x)
{
	ListNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data != x)
			cur = cur->next;
		else
			return cur;
	}
	return NULL;
}

顺序表与链表:

顺序表: 空间连续,可以随机访问;在中间插入和删除的复杂度O(N)
链表:不能随机访问;在任意位置插入和删除的实践复杂度为O(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值