数据结构基础-链表

链表的核心要素

每个节点由数据域和指针域组成

指针域指向下一个节点的内存地址

结构体的定义

typedef struct _LinkNode {
    ElemType data;
    struct _LinkNode* next;
}LinkList, LinkNode;

单链表

初始化

bool initList(LinkList*& L) {
	L = new LinkNode;
	if (!L) return false;
	L->next = NULL;
	return true;
}

增加元素

前插法

bool insertFrontList(LinkList*& L,LinkNode* node) {
	if (!L || !node) return false;
	node->next = L->next;
	L->next = node;
	return true;
}

尾插法

bool insertRearList(LinkList*& L, LinkNode* node) {
	if (!L || !node) return false;
	//找到最后一个节点
	LinkNode* last = NULL;
	last = L;
	while (last->next) last = last->next;
	node->next = NULL;
	last->next = node;
	return true;
}

插入元素

bool insertList(LinkList*& L, int pos, ElemType& e) {
	int j = 0;
	LinkList* p, * s;
	//在带头结点的单链表 L 中第 i 个位置插入值为 e 的新结
	p = L;
	while (p && j < pos - 1) {//查找第 i-1 个结点,p 指向该结点
		p = p->next;
		j++;
	}
	if (!p || j > pos - 1) return false;
	s = new LinkNode;
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;
}

遍历链表

void printList(LinkList*& L) {
	LinkNode* p;
	p = L->next;
	while (p) {
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}

获取元素

bool getElem(LinkList*& L, int pos, ElemType& e) {
	LinkList* p;
	int j = 1;
	p = L->next;
	while (p && j < pos) {
		p = p->next;
		j++;
	}
	if (!p || j > pos) return false;
	e = p->data;
	return true;
}

查找元素

bool findElem(LinkList*& L, ElemType e) {
	LinkList* p;
	p = L->next;
	while (p && p->data != e) {
		p = p->next;
	}
	if (!p) return false;

}

删除节点

bool deleteList(LinkList*& L, int pos) {
	int j = 0;
	LinkNode* p, * q;
	p = L;
	while (p->next && j < pos - 1) {
		p = p->next;
		j++;
	}
	if (!(p->next) || j > pos - 1) return false;
	q = p->next;
	p->next = q->next;
	delete q;
	return true;
}

销毁链表

void destroyList(LinkList*& L) {
	LinkList* p = L;
	cout << "销毁链表" << endl;
	while (p) {
		L = L->next;
		cout << "销毁节点" << p->data << endl;
		delete p;
		p = L;
	}
}

测试

int main() {
	LinkList* L = NULL;
	LinkNode* s = NULL;
	//1. 初始化一个空的链表
	initList(L);
	//2. 使用前插法插入数据
	int n;
	cout<<"前插法创建单链表"<<endl;
	cout<<"请输入元素个数 n:";
	cin>>n;
	cout<<"\n 请依次输入 n 个元素:" <<endl;
	while(n>0){
		s = new LinkNode; //生成新节点 s
		cin>>s->data;
		insertFrontList(L, s);
		n--;
	}
	//4. 单链表的输出
	printList(L);

	//5. 任意位置插入元素
	for (int j = 0; j < 3; j++) {
		int i, x;
		cout << "请输入插入的位置和元素(用空格隔开):";
		cin >> i;
		cin >> x;
		if (insertList(L, i, x)) {
			cout << "插入成功.\n\n";
		}
		else {
			cout << "插入失败!\n\n";
		}
		printList(L);
	}
	//6. 单链表根据位置获取元素
	int element = 0;
	if (getElem(L, 2, element)) {
		cout << "获取第二个元素成功, 值:" << element << endl;
	}
	else {
		cout << "获取第二个元素失败!" << endl;
	}
	//7. 单链表根据值查询元素所在的位置
	int index = 0;
	if (findElem(L, 10, index)) {
		cout << "查找元素 10 存在,所在位置: " << index << endl;
	}
	else {
		cout << "不存在元素 10." << endl;
	}
	//8. 单链表删除元素
	if (deleteList(L, 2)) {
		cout << "删除第 2 个元素成功!" << endl;
		printList(L);
	}
	else {
		cout << "删除第 2 个元素失败!" << endl;
	}
	//9. 销毁单链表
	destroyList(L);
	return 0;
}

循环链表

空的循环链表

例:有 10 个小朋友按编号顺序 1,2,。。。,10 顺时针方向围成一圈。从 1 号开 始顺时针方向 1,2,。。。,9 报数,凡报数 9 者出列(显然,第一个出圈为 编号 9 者)。 最后一个出圈者的编号是多少?第 5 个出圈者的编号是多少?

#include <iostream>
using namespace std;

typedef struct _LinkNode {
	int data;
	struct _LinkNode* next;
}LinkNode, LinkList;

bool initList(LinkList*& L) {
	L = new LinkNode;
	if (!L) return false;
	L->next = L;
	L->data = -1;
	return true;
}

bool insertRearList(LinkList*& L, LinkNode* node) {
	LinkNode* last = NULL;
	if (!L || !node) return false;
	last = L;
	while (last->next!=L) last = last->next;
	node->next = L;
	last->next = node;
	return true;
}

void printList(LinkList* L) {
	LinkList* p;
	if (!L || L == L->next) {
		cout << "链表为空" << endl;
		return;
	}
	p = L->next;
	while (p != L) {
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}

bool Joseph(LinkList*&L,int interval) {
	LinkList* p, * q;
	int i = 0, j = 0, times = 0, num = 0;
	p = L;
	if (!L || p->next == L) {
		cout << "链表为空!" << endl;
		return false;
	}
	if (interval < 1) {
		cout << "报数淘汰口令不能小于1" << endl;
		return false;
	}
	do {
		i += interval;
		while (p->next) {//查找第 i 个结点,p 指向该结点的上一个节点
			if (p->next != L) j++;
			if (j >= i) break;
			p = p->next;
		}
		times++;
		q = p->next;
		num = q->data;
		if (times == 5) cout << "第五个出圈的编号是:" << num << endl;
		printf("cur: %d last: %d next: %d\n", q->data, p->data, q->next->data);
		p->next=q->next;
		delete q;
		printList(L);
	} while (L->next != L);
	cout << "最后一个出圈的编号是:" << num << endl;
	return true;
}

int main() {
	int i, x;
	LinkList* L;
	LinkNode* s;
	//1. 初始化一个空的循环链表
	if (initList(L)) {
		cout << "初始化一个空的循环链表!\n";
	}
	//2. 创建循环链表(尾插法)
	cout << "尾插法创建循环链表, 插入 10 个元素..." << endl;
	i = 0;
	while ((++i) <= 10)
	{
		s = new LinkNode;//生成新结点
		s->data = i; //输入元素值赋给新结点的数据域
		s->next = NULL;
		if (insertRearList(L, s)) {
			cout << "插入成功!" << endl;
		}
		else {
			cout << "插入失败!" << endl;
		}
	}
	cout << "尾插法创建循环链表输出结果:\n";
	printList(L);
	//3. 解答约瑟夫问题
	Joseph(L, 9);
	return 0;
}

双链表

双链表定义

typedef struct _DbLinkNode {
	int data;
	struct _DbLinkNode* prev;
	struct _DbLinkNode* next;
}DbLinkNode, DbLinkList;

初始化双链表

bool initDbList(DbLinkList*& L) {
	L = new DbLinkNode;
	if (!L) return false;
	L->data = -1;
	L->next = NULL;
	L->prev = NULL;
	return true;
}

头插法创建双链表

bool insertFrontDbList(DbLinkList*& L, DbLinkNode* node) {
	if (L->next == NULL) {
		node->next = NULL;
		node->prev = L;
		L->next = node;
	}
	else {
		L->next->prev = node;
		node->next = L->next;
		node->prev = L;
		L->next = node;
	}
	return true;
}

尾插法创建双链表

bool insertRearDbList(DbLinkList*& L, DbLinkNode* node) {
	if (!L || !node) return false;
	DbLinkList* last = L;
	while (last->next) last = last->next;
	node->next = NULL;
	node->prev = last;
	last->next = node;
	return true;
}

指定位置插入元素

bool insertDbList(DbLinkList*& L, int i, int& e) {
	if (!L || !L->next) return false;
	if (i < 1) return false;
	int j = 0;
	DbLinkList * p, * s;
	p = L;
	while (p && j < i) {//查找位置为 i 的结点,p 指向该结点
		p = p->next;
		j++;
	}
	if (!p || j != i) {
		cout << "不存在节点:" << i << endl;
		return false;
	}
	cout << "p: " << p << endl;
	s = new DbLinkNode;//生成新节点
	s->data = e;
	s->next = p;
	s->prev = p->prev;
	p->prev->next = s;
	p->prev = s;
	return true;
}

遍历双链表

void printDbList(DbLinkList*& L) {
	DbLinkNode* p = NULL;
	if (!L) {
		cout << "链表为空." << endl;
		return;
	}
	p = L;
	while (p->next) {
		cout << p->next->data << "\t";
		p = p->next;
	}
	//逆向打印
	cout << endl << "逆向打印" << endl;
	while (p) {
		cout << p->data << "\t";
		p = p->prev;
	}
	cout << endl;
}

获取元素

bool getElemDbList(DbLinkList*& L, int i, int& e) {
	int index;
	DbLinkList* p;
	if (!L || !L->next) return false;
	p = L->next;
	index = 1;
	while (p && index < i) {//顺链表向后扫描,直到 p 指向第 i 个元素或 p 为空
		p = p->next; //p 指向下一个结点
		index++; //计数器 index 相应加 1
	}
	if (!p || index > i) {
		return false; //i 值不合法,i>n 或 i<=0
	}
	e = p->data;
	return true;
}

删除双链表

bool deleteDbList(DbLinkList*& L, int i) {
	DbLinkList* p;
	int index = 0;
	if (!L || !L->next) {
		cout << "双向链表为空!" << endl;
		return false;
	}
	if (i < 1) return false; //不能删除头节点
	p = L;
	while (p && index < i) {
		p = p->next;
		index++;
	}
	if (!p) { //当节点不存在时,返回失败
		return false;
	}
	p->prev->next = p->next; //改变删除结点前驱结点的 next 指针域
	p->next->prev = p->prev; //改变删除节点后继节点的 prev 指针域
	delete p; //释放被删除结点的空间
	return true;
}

销毁双链表

void destroyDbList(DbLinkList*& L) {
	//定义临时节点 p 指向头节点
	DbLinkList* p = L;
	cout << "销毁链表!" << endl;
	while (p) {
		L = L->next;//L 指向下一个节点
		cout << "删除元素: " << p->data << endl;
		delete p; //删除当前节点
		p = L; //p 移向下一个节点
	}
}

测试

int main() {
	DbLinkList* L = NULL;
	DbLinkNode* s = NULL;
	//1. 初始化一个空的双向链表
	initDbList(L);
	//2. 使用前插法插入数据
	int n;
	cout << "前插法创建双向链表" << endl;
	std::cout << "请输入元素个数 n:";
	cin >> n;
	cout << "\n 请依次输入 n 个元素:" << endl;
	while (n > 0) {
		s = new DbLinkNode; //生成新节点 s
		cin >> s->data;
		insertFrontDbList(L, s);
		n--;
	}
	//3. 使用尾插法插入数据
	cout << "尾插法创建双向链表" << endl;
	std::cout << "请输入元素个数 n:";
	cin >> n;
	cout << "\n 请依次输入 n 个元素:" << endl;
	while (n > 0) {
		s = new DbLinkNode; //生成新节点 s
		cin >> s->data;
		insertRearDbList(L, s);
		n--;
	}
	//4. 双向链表的输出
	printDbList(L);
	//5. 任意位置插入元素
	for (int j = 0; j < 3; j++) {
		int i, x;
		cout << "请输入插入的位置和元素(用空格隔开):";
		cin >> i;
		cin >> x;
		if (insertDbList(L, i, x)) {
			cout << "插入成功.\n\n";
		}
		else {
			cout << "插入失败!\n\n";
		}
		printDbList(L);
	}
	//6. 双向链表根据位置获取元素
	int element = 0;
	if (getElemDbList(L, 2, element)) {
		cout << "获取第二个元素成功, 值:" << element << endl;
	}
	else {
		cout << "获取第二个元素失败!" << endl;
	}
	//7. 双向链表删除元素
	if (deleteDbList(L, 2)) {
		cout << "删除第 2 个元素成功!" << endl;
		printDbList(L);
	}
	else {
		cout << "删除第 2 个元素失败!" << endl;
	}
	if (deleteDbList(L, 1)) {
		cout << "删除第 1 个元素成功!" << endl;
		printDbList(L);
	}
	else {
		cout << "删除第 1 个元素失败!" << endl;
	}
	//8. 销毁双向链表
	destroyDbList(L);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

run sun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值