复习_回顾所学_单链表(详解)_内含本人的小bug想知道是什么吗?


分享一下我的bug:


下面会有具体代码, 先留个悬念:
没有bug

//前插法
bool ListInsert_front(LinkList*& L, LinkNode* node)
{
	if (!L || !node) return false;

	node->next = L->next;
	L->next = node;
	
	return true;
}

有bug;

//前插法
bool ListInsert_front(LinkList*& L, LinkNode* node)
{
	if (!L || !node) return false;

	L->next = node;
	node->next = L->next;
	
	return true;
}

只要我把顺序换一下打印就会, 出bug, 你们知道为什么吗?
正确的:

node->next = L->next;
	L->next = node;

在这里插入图片描述
顺序乱的话:

L->next = node;
	node->next = L->next;

在这里插入图片描述
现实:
在这里插入图片描述


链表的算法实现:


单链表的概念
在这里插入图片描述
链表的节点均单向指向下一个节点,形成一条单向访问的数据链
在这里插入图片描述

单链表的初始化

typedef struct _LinkNode { 
	int data; //结点的数据域 
	struct _LinkNode *next; //结点的指针域 
}LinkNode, LinkList; //链表节点、链表 

bool InitList(LinkList* &L)//构造一个空的单链表 L 
{ 
	L=new LinkNode; //生成新结点作为头结点,用头指针 L 指向头结点 
	if(!L)return false; //生成结点失败 
	L->next=NULL; //头结点的指针域置空 
	return true; 
}

在这里插入图片描述
单链表增加元素

前插法

//前插法 
bool ListInsert_front(LinkList* &L, LinkNode * node){ 
	if(!L || !node ) return false; 

	node->next = L->next; 
	L->next = node; 
	return true; 
}

在这里插入图片描述

尾插法

//尾插法 
bool ListInsert_back(LinkList* &L, LinkNode *node){ 
	LinkNode *last = NULL; 
	
	if(!L || !node ) return false; 

	//找到最后一个节点 
	last = L; 
	while(last->next) last=last->next; 

	//新的节点链接到最尾部 
	node->next = NULL; 
	last->next = node; 
	return true; 
}

在这里插入图片描述

任意位置插入

//任意位置插法 
bool LinkInsert(LinkList* &L, int i, int &e)//单链表的插入
{
	 //在带头结点的单链表 L 中第 i 个位置插入值为 e 的新结点 
	int j; 
	LinkList *p, *s; 

	p=L; 
	j=0; 
	while (p&&j<i-1) //查找第 i-1 个结点,p 指向该结点 
	{ 
		p=p->next;
		 j++; 
	}

	if (!p || j>i-1){//i>n+1 或者 i<1 
		return false; 
	}

	s=new LinkNode; //生成新结点 
	s->data=e; //将新结点的数据域置为 e 
	s->next=p->next; //将新结点的指针域指向结点 ai 
	p->next=s; //将结点 p 的指针域指向结点 s 
	return true; 
}

在这里插入图片描述

单链表的遍历

void LinkPrint(LinkList* &L) //单链表的输出 
{ 
	LinkNode* p; 
	p=L->next; 
	
	while (p) 
	{ 
		cout <<p->data <<"\t"; 
		p=p->next; 
	}

	cout<<endl; 
}

单链表获取元素

bool Link_GetElem(LinkList* &L, int i, int &e)//单链表的取值 
{ 
	//在带头结点的单链表 L 中查找第 i 个元素 
	//用 e 记录 L 中第 i 个数据元素的值 
	int j; 
	LinkList* p; 

	p=L->next;//p 指向第一个结点, 
	j=1; //j 为计数器 

	while (j<i && p) //顺链域向后扫描,直到 p 指向第 i 个元素或 p 为空 
	{ 
		p=p->next; //p 指向下一个结点 
		j++; //计数器 j 相应加 1 
	}

	if (!p || j>i){ 
		return false; //i 值不合法 i>n 或 i<=0 
	}

	e=p->data; //取第 i 个结点的数据域 
	return true; 
}

单链表查找元素

bool Link_FindElem(LinkList *L, int e) //按值查找 
{ 
	//在带头结点的单链表 L 中查找值为 e 的元素 
	LinkList *p; 

	p=L->next; 
	
	while (p && p->data!=e){//顺链域向后扫描,直到 p 为空或 p 所指结点的 数据域等于 e 
		p=p->next; //p 指向下一个结点 
	}

	if(!p)return false; //查找失败 p 为 NULL 

	return true; 
}

单链表删除元素

bool LinkDelete(LinkList* &L, int i) //单链表的删除 
{ 
	//在带头结点的单链表 L 中,删除第 i 个位置 
	LinkList *p, *q; 
	int j; 
	p=L; 
	j=0; 

	while((p->next)&&(j<i-1)) //查找第 i-1 个结点,p 指向该结点 
	{ 
		p=p->next; 
		j++; 
	}

	if (!(p->next)||(j>i-1))//当 i>n 或 i<1 时,删除位置不合理 
		return false; 

	q=p->next; //临时保存被删结点的地址以备释放空间
	p->next=q->next; //改变删除结点前驱结点的指针域 
	delete q; //释放被删除结点的空间 
	return true; 
}

单链表销毁

void LinkDestroy(LinkList* &L) //单链表的销毁 
{ 
	//定义临时节点 p 指向头节点 
	LinkList *p = L; 
	cout<<"销毁链表!"<<endl; 

	while(p) 
	{ 
		L=L->next; //L 指向下一个节点 
		cout<<"删除元素: "<<p->data<<endl; 
		delete p; //删除当前节点 
		p=L; //p 移向下一个节点 
	}
}

具体代码:

#include <iostream>
#include <string>
#include <stdlib.h>

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 = NULL;
	L->data = -1;
	return true;
}


//前插法
bool ListInsert_front(LinkList*& L, LinkNode* node)
{
	if (!L || !node) return false;

	node->next = L->next;
	L->next = node;
	
	return true;
}


//尾插法
bool ListInsert_back(LinkList*& L, LinkNode* node)
{
	LinkNode* last = NULL;

	if (!L || !node) return false;

	last = L;

	while (last->next)
	{
		last = last->next;
	}

	node->next = NULL;
	last->next = node;

	return true;
}


//指定位置插入
bool LinkInsert(LinkList*& L, int i, int& e)
{
	if (!L) return false;

	int j = 0;
	LinkList* p, * s;

	p = L;

	while (p && j < i - 1) //查找位置为i-1的节点, p指向该结点
	{
		p = p->next;
		j++;
	}

	if (!p || j > i - 1)
	{
		return false;
	}

	s = new LinkNode;
	s->data = e;
	s->next = p->next;
	p->next = s;

	return true;
}


//打印
void LinkPrint(LinkList*& L)
{
	LinkNode* p = NULL;

	if (!L)
	{
		cout << "链表为空." << endl;
		return;
	}

	p = L->next;

	while (p)
	{
		cout << p->data << "\t";
		p = p->next;
	}

	cout << endl;
}


//单链表的取值
bool Link_GetElem(LinkList*& L, int i, int& e) //单链表的取值
{
	//在带头结点的单链表L中查找第i个元素
	//用e记录L中第i个数据元素的值

	int index;
	LinkList* 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 Link_FindElem(LinkList* L, int e, int& index)
{
	//在带头结点的单链表L中查找值为e的元素

	LinkList* p = NULL;
	p = L->next;
	index = 1;
	if (!L || !L->next)
	{
		index = 0;
		return false;
	}

	while (p && p->data != e)
	{
		p = p->next;
		index++;
	}

	if (!p)
	{
		index = 0;
		return false; //查无此值
	}

	return true;
}


//单链表的删除
bool LinkDelete(LinkList*& L, int i)
{
	LinkList* p, * q;

	int index = 0;
	p = L;

	if (!L || !L->next)
	{
		return false;
	}

	while ((p->next) && (index < i - 1))
	{
		p = p->next;
		index++;
	}

	if (!p->next || (index > i - 1)) //当 i>n 或 i<1 时, 删除位置不合理
	{
		return false;
	}

	q = p->next;		//临时保存被删结点的地址以备释放空间
	p->next = q->next;	//改变删除结点前驱结点的指针域
	delete q;			//释放被删除结点的空间

	return true;
}


//单链表的销毁
void LinkDestroy(LinkList*& L)
{
	//定义临时节点 p 指向头节点
	LinkList* p = L;
	cout << "销毁链表!" << endl;

	while (p)
	{
		L = L->next; //L指向下一个结点
		cout << "删除元素: " << p->data << endl;
		delete p; //删除当前节点
		p = L;	  //p 移向下一个节点
	}
}

int main()
{
	LinkList* L = NULL;
	LinkNode* s = NULL;



	//1. 初始化一个空的链表
	InitList(L);



	//2. 使用前插法插入数据
	int n;

	cout << "前插法创建单链表" << endl;
	cout << "请输入要插入的元素个数: ";
	cin >> n;
	cout << "\n请依次输入n个元素: " << endl;

	while (n > 0)
	{
		s = new LinkNode; //生成新节点 s

		cin >> s->data;
		if (ListInsert_front(L, s))
		{
			cout << "插入成功" << endl;
		}
		else
		{
			cout << "插入失败" << endl;
		}
		n--;
	}

	LinkPrint(L);



	//3. 使用尾插法插入数据
	int m = 0;

	cout << "尾插法创建单链表" << endl;
	cout << "请输入要插入元素个数: ";
	cin >> m;
	cout << "\n请依次输入 " << m << " 个元素: " << endl;

	while (m > 0)
	{
		s = new LinkNode; //生成新节点 s

		cin >> s->data;
		if (ListInsert_back(L, s))
		{
			cout << "插入成功" << endl;
		}
		else
		{
			cout << "插入失败" << endl;
		}
		m--;
	}
	LinkPrint(L);



	//5. 任意位置插入元素
	for (int j = 0; j < 2; j++)
	{
		int i = 0;
		int x = 0;
		cout << "请输入要插入的位置: ";
		cin >> i;
		cout << "请输入要插入的元素: ";
		cin >> x;

		if (LinkInsert(L, i, x))
		{
			cout << "插入成功.\n\n";
		}
		else
		{
			cout << "插入失败.\n\n";
		}
		LinkPrint(L);
	}


	//6. 单链表根据位置获取元素
	int element = 0;
	if (Link_GetElem(L, 2, element))
	{
		cout << "获取第 2 个元素成功, 值: " << element << endl;
	}
	else
	{
		cout << "获取第 2 个元素失败." << endl;
	}

	//7. 单链表根据值查询元素所在的位置
	int index = 0;
	if (Link_FindElem(L, 10, index))
	{
		cout << "查找元素 10 存在, 所在位置: " << index << endl;
	}
	else
	{
		cout << "不存在元素 10." << endl;
	}


	//8. 单链表删除元素
	if (LinkDelete(L, 2))
	{
		cout << "删除的 2 个元素成功" << endl;
	}
	else
	{
		cout << "删除第 2 个元素失败" << endl;
	}


	//9. 销毁单链表
	LinkDestroy(L);

	system("pause");
	return 0;
}

结语:

学到的知识要, 多复习, 多总结, 多敲. 自己写不出来的永远是别人的

分享一下我的技巧: 代数法把具体的数字带进去, 看看能能能找到规律.
还有就是画图, 也很重要.

我是小白, 如果存在问题, 欢迎大神给予评判指正.
错了不可怕, 可怕的是找不出bug

青春励志: 在最美的年龄, 为最纯的梦想, 进最大的努力!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

weifc-wei

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

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

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

打赏作者

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

抵扣说明:

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

余额充值