线性表-链表

本文介绍了链表数据结构的基础实现,包括带头结点的单链表初始化、指定位插入、删除及查找操作。通过示例代码详细阐述了每个操作的时间复杂度和实现细节,并提供了相应的辅助函数,如按值查找和获取链表长度。此外,还讨论了不带头结点的链表插入操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据结构-链表的基本实现

1.单链表

带头结点

InitList(LinkList& L) 初始化,时间复杂度O(1)

ListInsert(LinkList& L, int i, ElemType e) 指定位序后插,时间复杂度O(n)

ListDelete(LinkList& L, int i, ElemType& e) 位序删除元素,传回结点元素,时间复杂度O(n)

GetElem(LinkList L, int i) 按位查找,传回第一个结点元素等e的结点,时间复杂度O(n)

#include <iostream>
using namespace std;
#define ElemType int
#define MaxSize 2

typedef struct LNode {
	ElemType data;
	LNode* next;
}LNode, * LinkList;

//初始化,时间复杂度O(1)
bool InitList(LinkList& L) {
	L = new LNode; //创建带头结点
	if (L == NULL) {
		printf("内存分配失败\n");
		return false;
	}
	L->next = NULL;
	return true;
}
//指定位序后插,时间复杂度O(n)
bool ListInsert(LinkList& L, int i, ElemType e) {
	if (i < 1) {
		printf("插入位置错误,至少在第一位插入\n");
		return false;
	}
	LNode* p = L;//定义当前指针指向头结点
	int j = 0;//当前指针位于第几位结点
	while (p != NULL && j < i - 1) { //循环遍历,使当前指针指向插入位置的前一位
		p = p->next;
		j++;
	}
	/*****************/
	if (p == NULL) { //避免超出范围
		cout << "插入位置错误,最多在长度+1位(结尾)插入" << endl;
		return false;
	}
	//先令插入的结点next指向下一个结点
	//再让上一个结点(p)指向插入的结点
	LNode* s = new LNode;
	s->data = e;
	s->next = p->next;
	p->next = s;
	/*****************/  //可以直接用后面“InsertNextNode”函数简化
	return true;
}
//位序删除元素,传回结点元素,时间复杂度O(n)
bool ListDelete(LinkList& L, int i, ElemType& e) {
	if (i < 1) {
		printf("位序错误,位序从1开始\n");
		return false;
	}
	LNode* p = L;
	int j = 0;
	while (p != NULL && j < i - 1) {
		p = p->next;
		j++;
	}
	//判断第i-1个结点是否存在
	//判断是否结尾(if i = 4,长度为3,i-1个结点为结尾,i超出范围)
	if (p == NULL || p->next == NULL) {
		printf("位序超出范围\n");
		return false;
	}
	LNode* d = p->next;
	e = d->data;
	p->next = d->next;
	delete d; //释放结点空间
	return true;
}

//按位查找,传回第一个结点元素等e的结点,时间复杂度O(n)
LNode* GetElem(LinkList L, int i) {
	if (i < 1) {
		cout << "位序错误" << endl;
		return NULL;
	}
	LNode* p = L;
	int j = 0;
	while (p != NULL && j < i) {
		p = p->next;	//if i>长度,p=NULL
		j++;
	}
	return p;
}

void PrintList(LinkList L) {
	printf("链表元素为:");
	for (LNode* p = L->next; p != NULL; p = p->next) {
		printf("%d ", p->data);
	}
	printf("\n");
}

void Insert(LinkList&L) {
	int i;
	ElemType e;
	printf("请输入插入位置和元素:");
	scanf("%d%d", &i,&e);
	ListInsert(L, i, e);
	PrintList(L); //调用函数,输出链表
}

void Delete(LinkList &L) {
	int i;
	ElemType e;
	printf("请输入需要删除元素的位置:");
	scanf("%d", &i);
	if (ListDelete(L, i, e)) {
		printf("第%d位元素:%d 已删除!\n", i, e);
	}
	else {
		printf("删除失败!\n");
	}
}

void Search(LinkList L) {
	int i;
	LNode* p;
	printf("请输入元素位置查找:");
	scanf("%d", &i);
	p = GetElem(L, i); //不存在则返回NULL
	if (p != NULL) { 
		printf("第%d位元素为:%d\n", i, p->data);
	}
	else {
		printf("位序超出范围!\n");
	}
}
void menu()
{
	printf("*********** 1.指定位序插入 2.指定位序删除 3.打印链表 4.指定位序查找 ***********\n");
}

int main()
{
	LinkList L;
	int choice;
	InitList(L);
	while (true)
	{
		menu();
		printf("请输入菜单序号:");
		scanf("%d", &choice);
		switch (choice)
		{
		case 1:Insert(L); break;
		case 2:Delete(L); break;
		case 3:PrintList(L); break;
		case 4:Search(L); break;
		default:printf("输入错误!!!\n");
		}
	}
}

其他操作
//指定结点前插,时间复杂度O(1)
/*因为指定结点的前一个结点是未知的
所以无法实现前驱结点指针->next = s
但可以指定结点称为前驱结点,交换数据
*/
bool InsertPriorNode(LNode* p, ElemType e) {
	if (p == NULL) {
		printf("指定结点为空\n");
		return false;
	}
	LNode* s = new LNode;
	s->data = p->data; //交换数据
	p->data = e;
	s->next = p->next;
	p->next = s;
	return true;
}

//按值查找,传回第一个结点元素等e的结点,时间复杂度O(n)
LNode* LocateElem(LinkList L, ElemType e) {
	LNode* p = L->next;//当前指针指向第一数据结点
	while (p != NULL && p->data != e) {
		p = p->next;
	}
	return p;
}

//获取链表长度,时间复杂度O(n)
int ListLength(LinkList L) {
	LNode* p = L;
	int len = 0;
	while (p->next != NULL) {
		p = p->next;
		len++;
	}
	/*或者
	for (LNode* p = L; p->next != NULL; p = p->next) {
		len++;
	}
	*/
	return len;
}
不带头结点
bool InitList(LinkList& L) {
	L = NULL; //空表,防止脏数据,同时也为了后面插入操作,结点指向NULL
	return true;
}
//指定位序插入,时间复杂度O(n)
bool ListInsert(LinkList& L, int i, ElemType e) {
	if (i < 1) {
		cout << "插入位置错误,至少在第一位插入" << endl;
		return false;
	}
	else if (i == 1) {
		LNode* s = new LNode;
		s->data = e;
		s->next = L; //第一次插入结点时,L=NULL
		L = s;
		return true;
	}
	LNode* p = L;//定义当前指针指向第1个结点
	int j = 1;//当前指针指向第1位结点
	while (p != NULL && j < i - 1) { //循环遍历,使当前指针指向插入位置的前一位
		p = p->next;
		j++;
	} 
	if (p == NULL) { //避免超出范围
		cout << "插入位置错误,最多在长度+1位插入" << endl;
		return false;
	}
	//先令插入的结点next指向下一个结点
	//再让上一个结点(p)指向插入的结点
	LNode* s = new LNode;
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值