栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

数据结构(初阶)——顺序表、链表

Java 更新时间:发布时间: 百科书网 趣学号
一、顺序表

SeqList.h

#pragma once
#include
#include
#include
#include
#include
typedef int SLDataType;
// 顺序表的动态存储
typedef struct SeqList
{
	SLDataType* array; // 指向动态开辟的数组
	size_t size; // 有效数据个数
	size_t capicity; // 容量空间的大小
}SeqList;
SeqList SL;
// 基本增删查改接口
// 顺序表初始化
void SeqListInit(SeqList* psl);

// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* psl);

// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x);

// 顺序表尾删
void SeqListPopBack(SeqList* psl);

// 顺序表头插
void SeqListPushFront(SeqList* psl, SLDataType x);

// 顺序表头删
void SeqListPopFront(SeqList* psl);

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

// 顺序表在pos位置插入x
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x);

// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos);

// 顺序表销毁
void SeqListDestory(SeqList* psl);

// 顺序表打印
void SeqListPrint(SeqList* psl);

//顺序表修改
void SLModify(SeqList* psl, size_t pos, SLDataType x);

SeqList.c

#define _CRT_SECURE_NO_WARNINGS 

#include "SeqList.h"

// 顺序表初始化
void SeqListInit(SeqList* psl) {
	assert(psl);

	psl->capicity = 0;
	psl->size = 0;
	psl->array = NULL;
	

}

 //顺序表打印
void SeqListPrint(SeqList* psl) {
	assert(psl);
	for (int i = 0; i < psl->size; i++) {
		printf("%d ", psl->array[i]);
	}

}

// 顺序表头插
void SeqListPushFront(SeqList* psl, SLDataType x) {
	assert(psl);

	//检查空间是否足够
	 CheckCapacity(&psl);
	 int temp_size = psl->size;
	 while (temp_size > 0) {

		 psl->array[temp_size] = psl->array[temp_size-1];
		 temp_size--;

	 }
	 psl->array[0] = x;
	 psl->size++;

}

// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x) {
	assert(psl);

	//检查空间是否足够
	CheckCapacity(&psl);

	psl->array[psl->size] = x;
	psl->size++;

}

// 顺序表销毁
void SeqListDestory(SeqList* psl) {

	assert(psl);
	free(psl->array);
	psl->array = NULL;
	psl->capicity = 0;
	psl->size = 0;

}
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList** psl) {

	if ((*psl)->capicity == 0) {
		SLDataType* temp = NULL;
		(*psl)->capicity = 4 * sizeof(SLDataType);
		temp = (SLDataType)malloc((*psl)->capicity);
		if (temp == NULL) {
			perror(CheckCapacity);
			return 0;
		}
		(*psl)->array = temp;

		return;
	}

	if ((*psl)->capicity <= (*psl)->size*sizeof(SLDataType)) {
		(*psl)->capicity *= 2;
		SLDataType* temp = NULL;
		//检查开辟是否成功
		temp = (SLDataType)realloc((*psl)->array,(*psl)->capicity);

		if (temp == NULL) {
			perror(CheckCapacity);
			return 0;
		}
		(*psl)->array = temp;
	}

}

// 顺序表尾删
void SeqListPopBack(SeqList* psl) {

	assert(psl);

	psl->size--;
}

// 顺序表头删
void SeqListPopFront(SeqList* psl) {
	assert(psl);

	int temp_size = 1;
	while (temp_size <= psl->size) {

		psl->array[temp_size-1] = psl->array[temp_size];
		temp_size++;

	}
	psl->size--;

}
// 顺序表查找
int SeqListFind(SeqList* psl, SLDataType x) {
	assert(psl);
	//找到返回下标
	for (int i = 0; i < psl->size; i++) {
		if (psl->array[i] == x) {

			return i;
		}
	}
	//没找到返回-1;
	return -1;
}


// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos) {

	assert(psl);
	assert(pos < psl->size);
	if (pos >= psl->size) {
		printf("删除超出范围限制");
		return ;
	}

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

// 顺序表在pos位置插入x
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x) {

	assert(psl);
	assert(pos <= psl->size);

	CheckCapacity(&psl);

	int temp = psl->size;
	while (temp > pos) {
		psl->array[temp] = psl->array[temp - 1];
		temp--;
	}
	psl->array[pos] = x;
	psl->size++;
}

//修改
void SLModify(SeqList* psl, size_t pos, SLDataType x) {

	assert(psl);
	assert(pos < psl->size);
	
	psl->array[pos] = x;

}
二.单链表

单链表.h

#pragma once
#include
#include
#include

typedef int SLTDateType;
typedef struct SListNode
{
	SLTDateType data;
	struct SListNode* next;
}SListNode;
// 动态申请一个结点
SListNode* BuySListNode(SLTDateType x);
// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 单链表的尾删
void SListPopBack(SListNode** pplist);
// 单链表头删
void SListPopFront(SListNode** pplist);
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
void SListInsertAfter(SListNode* pos, SLTDateType x);
// 单链表 之前插入(难)
void SListInsertBefore(SListNode* pos, SLTDateType x);
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode* pos);
// 单链表销毁
void SLlistDestory(SListNode* phead);
//单链表删除当前位置
void SListErase(SListNode* pos);

单链表.c

#define _CRT_SECURE_NO_WARNINGS
#include"单链表.h"

SListNode* BuySListNode(SLTDateType x) {

	SListNode* temp = (SListNode*)malloc(sizeof(SListNode));

	if (temp == NULL) {
		perror("malloc fail");
		exit(-1);
	}
	SListNode* newnode = temp;
	temp = NULL;

	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

// 单链表打印
void SListPrint(SListNode* phead) {

	SListNode* cur = phead;

	while (cur) {
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULLn");

}

// 单链表的头插
void SListPushFront(SListNode** pphead, SLTDateType x) {   //改变一级指针就需要一级指针的地址,所以传入二级指针
	assert(pphead);
	SListNode* newnode = BuySListNode(x);

	newnode->next = *pphead;
	*pphead = newnode;

}

// 单链表尾插
void SListPushBack(SListNode** pphead, SLTDateType x) {
	assert(pphead);
	//单链表不为空
	if (* pphead == NULL ) {
		SListNode* next = BuySListNode(x);
		*pphead = next;
		

	}//单链表为空
	else {
		SListNode* cur = *pphead;
		while (cur->next != NULL) {
			cur = cur->next;
		}

		SListNode* next = BuySListNode(x);
		cur->next = next;
	}

}
// 单链表头删
void SListPopFront(SListNode** pphead) {
	
	assert(pphead);
	if (*pphead == NULL) {
		return;
	}
	SListNode* del = *pphead;
	*pphead = (*pphead)->next;
	free(del);
	del = NULL;

}

// 单链表的尾删
void SListPopBack(SListNode** pphead) {

	assert(pphead);
	if (*pphead == NULL) {
		return;
	}
	if ((*pphead)->next == NULL) {
		free(*pphead);
		*pphead = NULL;
		return;
	}
	SListNode* cur = *pphead;

	while (cur->next->next != NULL) {
		cur = cur->next;
	}
	free(cur->next);
	cur->next = NULL;


}
// 单链表查找
SListNode* SListFind(SListNode* pphead, SLTDateType x) {

	assert(pphead);
	SListNode* cur = pphead;

	while (cur) {
		if (x == cur->data) {
			printf("找到了n");
			return cur;
		}
		else {
			cur = cur->next;
		}

	}
	return NULL;

}


//单链表在某位置之后插入
void SListInsertAfter(SListNode** pphead,SListNode* pos, SLTDateType x) {

	assert(pphead);

	if (*pphead == NULL) {
		SListPushFront(pphead, x);
		return;
	}
	
	SListNode* newcode =  BuySListNode(x);
	newcode->next = pos->next;//注意这两行的顺序
	pos->next = newcode;

}
// 单链表 之前插入(难)
void SListInsertBefore(SListNode** pphead, SListNode* pos, SLTDateType x) {

	assert(pos);
	assert(pphead);

	if (*pphead == NULL) {
		SListPushFront(pphead, x);
		return;
	}

	//方法一:找到前一项的next
	SListNode* cur = *pphead;
	if (pos == pphead) {
		SListPushFront(pphead, x);
		return;
	}
	while (cur->next != pos) {

		cur = cur->next;

		//找不到,说明pos传错了
		assert(cur);
	}
	SListNode* newcode = BuySListNode(x);
	newcode->next = pos;
	cur->next = newcode;
	//方法二 顺序法交换

	//SListNode* newcode = BuySListNode(pos->data);
	//pos->data = x;


}
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode** pphead, SListNode* pos) {

	assert(pphead);
	assert(pos);
	
	if (pos->next == NULL) {
		SListPopBack(pphead);
		return;
	}
	SListNode* cur = pos->next;
	pos->next = pos->next->next;

	free(cur);
}


//单链表删除当前位置
void SListErase(SListNode** pphead, SListNode* pos) {
	assert(pphead && pos);

	if (pos == *pphead) {
		SListPopFront(pphead);
		return;
	}

	SListNode* cur = pos->next->next;
	pos->data = pos->next->data;
	free(pos->next);
	pos->next = cur;

}


// 单链表销毁
void SLlistDestory(SListNode** pphead) {

	assert(pphead);
	SListNode* cur = pphead;
	SListNode* next = pphead;
	while (cur) {
		next = cur->next;
		free(cur);
		cur = next;
	}

	pphead = NULL;

}

三.带头双向循环链表

List.h

#pragma once
#include
#include
#include

typedef int LTDataType;
typedef struct ListNode
{
	LTDataType _data;
	struct ListNode* next;
	struct ListNode* prev;
}ListNode;
// 创建返回链表的头结点.
ListNode* ListCreate();
//双向链表创造一个新节点
ListNode* ListBuyNode(LTDataType x);
// 双向链表打印
void ListPrint(ListNode* plist);
// 双向链表尾插
void ListPushBack(ListNode* plist, LTDataType x);
// 双向链表头插
void ListPushFront(ListNode* plist, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* plist);
// 双向链表头删
void ListPopFront(ListNode * plist);
// 双向链表查找
ListNode* ListFind(ListNode* plist, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的结点
void ListErase(ListNode* pos);
// 双向链表销毁
void ListDestory(ListNode* plist);



List.c

#define _CRT_SECURE_NO_WARNINGS 
#include"List.h"

// 创建返回链表的头结点.
ListNode* ListCreate() {
	ListNode* ListGuard = (ListNode*)malloc(sizeof(ListNode));
	if (ListGuard == NULL) {
		perror("ListGuard malloc fai");
		exit(-1);
	}
	ListGuard->next = ListGuard;
	ListGuard->prev = ListGuard;
	return ListGuard;
}

// 双向链表打印
void ListPrint(ListNode* plist) {
	assert(plist);
	ListNode* head = plist;
	ListNode* cur = head->next;

	printf("head<=>");
	while (cur != head) {
		printf("%d<=>", cur->_data);
		cur = cur->next;
	}
	printf("n");
}
//双向链表创造一个新节点
ListNode* ListBuyNode(LTDataType x) {
	ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
	if (newNode == NULL) {
		perror("newNode malloc fail");
		exit(-1);
	}
	newNode->next = NULL;
	newNode->prev = NULL;
	newNode->_data = x;
	return newNode;
}
// 双向链表尾插
void ListPushBack(ListNode* plist, LTDataType x) {
	assert(plist);
	ListNode* tail = plist->prev;

	ListNode* newNode = ListBuyNode(x);
	//节点四步走 注意语句顺序!
	newNode->next = plist;
	plist->prev = newNode;
	tail->next = newNode;
	newNode->prev = tail;

}
// 双向链表头插
void ListPushFront(ListNode* plist, LTDataType x) {
	assert(plist);
	ListNode* first = plist->next;

	ListNode* newNode = ListBuyNode(x);
	//节点四步走 注意语句顺序!
	first->prev = newNode;
	newNode->next = first;
	plist->next = newNode;
	newNode->prev = plist;

}
//检查双向列表是否为空
int CheckList(ListNode* plist) {
	assert(plist);
	//返回“真”为空 返回"假"为非空;
	return plist->next == plist->prev;
}
// 双向链表尾删
void ListPopBack(ListNode* plist) {
	assert(plist);
	assert(!CheckList(plist));
	ListNode* tail = plist->prev;

	//节点链接
	tail->prev->next = plist;
	plist->prev = tail->prev;
	//释放
	free(tail);
}
// 双向链表头删
void ListPopFront(ListNode* plist) {
	assert(plist);
	assert(!CheckList(plist));
	ListNode* first = plist->next;

	//节点链接
	plist->next = first->next;
	first->next->prev = plist;

	//释放
	free(first);
}
// 双向链表查找
ListNode* ListFind(ListNode* plist, LTDataType x) {
	assert(plist);
	if (CheckList(plist)) {
		printf("链表为NULL,无法查找有效数据n");
		exit(-1);
	}
	ListNode* cur = plist->next;
	while (cur != plist) {
		if (cur->_data == x) {
			printf("找到啦n");
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x) {
	assert(pos);
	ListNode* first = pos->prev;
	ListNode* second = pos;
	ListNode* newNode = ListBuyNode(x);

	newNode->next = second;
	second->prev = newNode;
	first->next = newNode;
	newNode->prev = first;

}
// 双向链表删除pos位置的结点
void ListErase(ListNode* pos) {
	assert(pos);
	ListNode* first = pos->prev;
	ListNode* del = pos;
	ListNode* second = pos->next;

	first->next = second;
	second->prev = first;
	free(del);
}
// 双向链表销毁
void ListDestory(ListNode* plist) {
	assert(plist);
	ListNode* cur = plist->next;
	ListNode* next = NULL;
	plist->next = NULL;
	while (cur != NULL) {
		next = cur->next;
		free(cur);
		cur = next;
	}
	printf("销毁成功n");
}
四、顺序表、链表 oj

 顺序表

1. 原地移除数组中所有的元素 val ,要求时间复杂度为 O(N) ,空间复杂度为 O(1) 。 力扣 2. 删除排序数组中的重复项。 力扣 3. 合并两个有序数组。

力扣

链表

1. 删除链表中等于给定值 val 的所有结点  力扣 2. 反转一个单链表。 力扣 3. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则 返回第二个中间结点。 力扣 4. 输入一个链表,输出该链表中倒数第 k 个结点。 链表中倒数第k个结点_牛客题霸_牛客网 5. 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有 结点组成的。 力扣 6. 编写代码,以给定值 x 为基准将链表分割成两部分,所有小于 x 的结点排在大于或等于 x 的结 点之前 。 链表分割_牛客题霸_牛客网 7. 链表的回文结构。 链表的回文结构_牛客题霸_牛客网 8. 输入两个链表,找出它们的第一个公共结点。 力扣 9. 给定一个链表,判断链表中是否有环。 力扣 【思路】 快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表其实位置开始运行, 如果链表 带环则一定会在环中相遇,否则快指针率先走到链表的末尾。比如:陪女朋友到操作跑步减 肥。 10. 给定一个链表,返回链表开始入环的第一个结点。 如果链表无环,则返回 NULL 力扣 11. 给定一个链表,每个结点包含一个额外增加的随机指针,该指针可以指向链表中的任何结点 或空结点。 要求返回这个链表的深度拷贝。 力扣 12. 其他 。 ps :链表的题当前因为难度及知识面等等原因还不适合我们当前学习,以后大家自己 下去以后 力扣 +  牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推,求职就业一站解决_牛客网
顺序表优点: 1.尾插、尾删效率高。 2.可以随机访问。. (了解)3.cpu高速缓存命中率更高(相比链表) 顺序表缺点: 1.头部中部插入效率低——O(N) 2.扩容 ——性能消耗,空间浪费
链表优点: 1.任意插入删除都很方便 2.扩容——不存在空间浪费(按需申请空间) 链表缺点: 1.扩容——每次都要申请malloc浪费了时间 2.不能随机访问

 

转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/1065134.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号