数据结构之单向链表操作1-(插入,删除,交换,反转,排序等操作)

本文详细介绍了单向链表的基本概念、实现方式及常见操作,包括创建、插入、删除、查找、获取元素、反转链表等,并通过实例代码展示链表的使用方法。

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

第一次写博客,也是为了激励自己学习,可能还不太懂(~ ̄▽ ̄)~,而且代码上可能还有些不太足,敬请赐教!!!


如标题所示,这次演示单向链表的一些基本的操作,有些地方可能没有考虑周到,ORZ~

首先是些基本的声明如下

template<typename T>		
struct Node{		//结点
	T data;
	Node * next;
};		

template<typename T>
class LinkList{
private:
	Node<T> * head;		//头指针	
public:
	LinkList();				//创建容量为m的空表
	~LinkList();
	void CreateList(int n);		//创建表长为n的线性表
	void Insert(int i, T e);	//在i位置插入值e
	T Delete(int i);			//删除i位置的值并返回它
	int Locate(T e);			//通过给定值查找线性表中第一个等于此值的数,返回其序列号
	T GetElem(int i);			//获取i位置的值
	T Prior(T e);				//返回元素e的前驱
	int Length();				//返回表长
	bool Empty();				//检查表是否为空
	void Clear();				//清空表
	void LinkListTraverse();	//遍历表中的元素
	void Reverse();				//反转链表
	Node<T> * FindNode(int i);	//通过给定序号返回结点
	Node<T> * FindPro(int i);		//通过给定序号返回前驱结点
	void Exchange(int i, int j);	//交换链表中的两个结点
	void InsertSort();			//插入排序链表
};


函数的定义


template<typename T>
LinkList<T>::LinkList()
{
	head = new Node<T>;
	if (!head)
		throw "内存分配失败 \n";
	head->next = NULL;              //建立带头结点的链表
}

//删除结点,释放内存
template<typename T>
LinkList<T>::~LinkList()
{
	Node<T> *p;		//临时结点指针,保存要释放的结点
	while (head)
	{
		p = head;
		head = head->next;        //通过让p保存当前要释放的结点,然后让head往下移动,再释放p指向的空间,循环如此达到完全释放
		delete p;
	}
}

//尾插法
template<typename T>
void LinkList<T>::CreateList(int n)
{
	Node<T> *p = head, *s;		//p保存当前结点,s指向新结点
	cout << "输入数据: ";
	for (int i = 0; i < n; ++i)
	{
		s = new Node<T>;
		cin >> s->data;
		s->next = p->next;      //让p从头结点开始,再把新结点接到p结点后面
		p->next = s;
		p = s;                  //接完后,再让p结点指向新结点,循环
	}
}

////头插法,比尾插法少了p保存新结点,这样让每次新结点都在头插入
//template<typename T>
//void LinkList<T>::CreateList(int n)
//{
//	cout << "输入数据: ";
//	for (int i = 0; i < n; ++i)
//	{
//		s = new Node<T>;
//		cin >> s->data;
//		s->next = head->next;
//		head->next = s;
//	}
//}

//返回表长(不包含头结点)
template<typename T>
int LinkList<T>::Length()
{
	int i = 0;
	Node<T> * p = head->next;	//p指向首结点开始计数
	while (p)
	{
		++i;
		p = p->next;
	}

	return i;
}

//在i位置插入值e
template<typename T>
void LinkList<T>::Insert(int i, T e)
{
	Node<T> * p = head, * s;
	int cnt = 1;		//计数
	while (p && cnt < i)
	{
		p = p->next;		//定位到i-1的位置
		cnt++;
	}
	if (!p || cnt > i)
		throw "插入位置出错 \n";		//i大于表长或者小于0
	s = new Node<T>;
	if (!s)
		throw "内存分配失败 \n";
	s->data = e;
	s->next = p->next;
	p->next = s;
}

//删除i位置的值并返回它
template<typename T>
T LinkList<T>::Delete(int i)
{
	if (Length() == 0)
		throw "无元素存在,不需要删除 \n";
	Node<T> *p = head;
	int j = 1;
	while (p && j < i)
	{
		p = p->next;
		j++;
	}
	if (!p || j > i)
		throw "插入位置出错 \n";
	T e = p->next->data;
	Node<T> *s = p->next;     //保存要释放的结点
	p->next = p->next->next;
	delete s;

	return e;
}
//通过给定值查找线性表中第一个等于此数,返回其序列号
template<typename T>
int LinkList<T>::Locate(T e)
{
	Node<T> *p = head->next;
	int cnt = 0;
	while (p)
	{
		cnt++;
		if (p->data == e)
			return cnt;			//返回序列号
		p = p->next;
	}
	cout << "没有找到元素 \n";
	return 0;				//返回0表示没有找到
}

//获取i位置的值
template<typename T>
T LinkList<T>::GetElem(int i)
{
	Node<T> *p = head->next;
	int j = 1;
	while (p && j < i)
	{
		p = p->next;
		j++;			//定位到i位置,注意和前面定位到i-1的区别
	}
	if (!p || j > i)
		throw "插入位置出错 \n";
	return p->data;
}

template<typename T>
//返回元素e的前驱
T LinkList<T>::Prior(T e)
{
	Node<T> *p = head->next;
	int cnt = 0;
	while (p)
	{
		cnt++;
		if (p->next->data == e)
			return p->data;
		p = p->next;
	}
	cout << "没有找到元素 \n";
	return 0;				//返回0表示没有找到
}

//检查表是否为空
template<typename T>
bool LinkList<T>::Empty()
{
	int len = Length();
	return len == 0;         
}

//清空表(和析构函数完全摧毁链表相比,保留头结点)
template<typename T>
void LinkList<T>::Clear()
{
	Node<T> * p = head->next;
	while (p)
	{
		Node<T> * s = p;
		p = p->next;
		delete s;
	}
	head->next = NULL;      //最后记得要将头结点的next置空
}

template<typename T>
//遍历表中的元素
void LinkList<T>::LinkListTraverse()
{
	Node<T> *p = head->next;
	while (p)
	{
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}

//反转链表
template<typename T>
void LinkList<T>::Reverse()
{
	if (head == NULL)
		return;
	Node<T> *curr, *p;		  //curr一直指向首结点
	curr = head->next;
	while (curr->next != NULL)
	{
		p = curr->next;
		curr->next = p->next;
		p->next = head->next;     
		head->next = p;
	}
}

//通过给定序号返回结点
template<typename T>
Node<T> * LinkList<T>::FindNode(int i)
{
	Node<T> *p = head;
	int j = 0;
	while (p && j < i)
	{
		j++;
		p = p->next;		//当j = i时,j实际计数实在i后面一位
	}						//此时p指向i位置的
	if (!p || j > i)
		throw"位置异常 \n";
	return p;
}

//通过给定序号返回前驱结点
template<typename T>
Node<T> * LinkList<T>::FindPro(int i)
{

	Node<T> *p = head;
	int j = 1;
	while (p && j < i)
	{
		j++;
		p = p->next;
	}
	if (!p || j > i)
		throw"位置异常 \n";
	return p;		//返回前驱结点
}

//交换链表中的两个结点
template<typename T>
void LinkList<T>::Exchange(int i, int j)
{
	/*1. 假如两个结点相等, 不交换
	 *2. 两个结点相邻特殊处理
	 *3. 一般情况直接处理
	 */

	//分别找到待交换结点的前驱与后继
	Node<T> * node1 = FindNode(i), * node2 = FindNode(j);	
	Node<T> * prenode1 = FindPro(i), * prenode2 = FindPro(j);
	Node<T> * postnode1 = node1->next, * postnode2 = node2->next;
	if (node1 == node2)
	{
		cout << "两个结点相等 \n";
		return;
	}
	
	//特殊情况处理
	if (prenode2 == node1)		//结点1在结点2的前面
	{
		prenode1->next = node2;
		node2->next = node1;
		node1->next = postnode2;
		return;
	}
	if (prenode1 == node2)
	{
		prenode2->next = node1;
		node1->next = node2;
		node2->next = postnode1;
		return;
	}

	//一般情况直接交换两个结点
	prenode1->next = node2;
	node2->next = postnode1;
	prenode2->next = node1;
	node1->next = postnode2;

}

//插入排序链表
template<typename T>
void LinkList<T>::InsertSort()
{
	Node<T> *first;			//作为无序链表的第一个结点
	Node<T> *t;				//作为无序链表的待插结点
	Node<T> *p, *q;			//作为临时变量
	if (head->next == NULL)
		return;				//保证有结点
	first = head->next->next;	//first指向链表的第二个结点(不包含头结点)
	head->next->next = NULL;

	while (first != NULL)
	{
		for (t = first, q = head->next, p = head; q && q->data < t->data; p = q, q = q->next);		//找到第一个比t->data大的结点
		first = first->next;	//往下移动
		p->next = t;
		t->next = q;
	}
}

主函数

int main(){
	int i, j;
	LinkList<int> LList;

	cout << "请输入你需要的链表表实际长度:";
	cin >> i;
	LList.CreateList(i);
	cout << "表中元素为:";
	LList.LinkListTraverse();
	cout << "插入元素后: \n";
	LList.Insert(2, 33);
	LList.Insert(4, 66);
	cout << "表中元素为:";
	LList.LinkListTraverse();
	cout << "表的长度为:" << LList.Length() << endl;
	cout << "现在进行删除操作: \n";
	cout << "请输入你需要删除的位置:";
	cin >> i;
	cout << "删除的元素为:" << LList.Delete(i) << endl;
	if (LList.Empty())
		cout << "表为空 \n";
	else
		cout << "表不为空 \n";
	cout << "表中元素为:";
	LList.LinkListTraverse();
	cout << "反转链表:";
	LList.Reverse();
	cout << "表中元素为:";
	LList.LinkListTraverse();
	cout << "输入要交换两个结点的序列号:";
	cin >> i >> j;
	LList.Exchange(i, j);		//交换两个结点
	cout << "表中元素为:";
	LList.LinkListTraverse();
	cout << "获取位置4的元素为:" << LList.GetElem(4) << endl;
	cout << "请输入一个链表中存在的数:";
	cin >> i;
	cout << "其序列号为:" << LList.Locate(i) << endl;
	cout << "其前驱元素为:" << LList.Prior(i) << endl;
	cout << "现在进行链表的排序(根据关键字数据大小排序) \n";
	LList.InsertSort();
	cout << "表中元素为:";
	LList.LinkListTraverse();

	LList.Clear();
	cout << "将表中元素清空后: \n";
	if (LList.Empty())
		cout << "表为空 \n";
	else
		cout << "表不为空 \n";

	return 0;
}
难点我觉得应该在于链表反转,排序,有时间再补上解释!(。・_・)/~~~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值