回顾单链表,堆栈,队列,双链表数据结构

这篇博客探讨了数据结构中的链表实现,包括如何使用数组或双端链表封装堆栈和队列。作者指出树型结构是数据结构中的难点,特别是多叉树、二叉树、平衡二叉树等,它们之间的关系和区别尚未清晰掌握。博客提供了单链表的实现,包括插入、删除、反转和打印等操作,并附带了一个简单的主函数示例来演示链表操作。
摘要由CSDN通过智能技术生成

这几个数据结构还是比较通俗易懂的,其中堆栈和队列可以用数组封装实现,也可以用双端链表实现,等等不多复述。个人感觉数据结构真正复杂的是树型结构,多叉树,二叉树,平衡二叉树,B+树,B-树,红黑树,他们关系和区别,目前也说不清楚。这一块是我感觉很薄弱的地方。

简单写了个单链表,其他的懒得写了,下篇开始搞搞树型结构

P2.h

#pragma once
#include <iostream>
 
using namespace std;

template <class T>
class P2
{
public:
	P2();
	~P2();
	void insert(T v);
	void remove(T v);
	
	void deleteList();
	bool isNull();
	
	void reverseList();
	void createList(T v);
	void printfList();
	class Node
	{
	public:
		Node();
		Node(T v);
		~Node();

		T m_value;
		Node* m_next;
	};
	T getByIndex(int i);
private:
	Node* m_head;
	int m_size;
	

};

 


P2.cpp

#include "P2.h"
#include <iostream>
using namespace std;
template <class T>
P2<T>::P2()
{
}

template <class T>
P2<T>::~P2()
{
	deleteList();
}
 
template <class T>
void P2<T>::insert(T v)
{
	if (isNull())
	{
		createList(v);
	}
	Node *p = m_head;

	for (int i = 0; i < m_size-1; i++)
	{
		p = p->m_next;
	}
	Node * n = new Node(v);
	p->m_next = n;
	m_size++;
}

template <class T>
void P2<T>::remove(T v)
{
	if (isNull())
	{
		return;
	}
	Node*p = m_head;
	Node *pre = NULL;
	while (p != NULL)
	{
		if (p->m_value == v)
		{
			if (pre != NULL)
			{
				pre->m_next = p->m_next;
			}
			else
			{
				m_head = p->m_next;
			}
			delete(p);
			m_size--;
			if (m_size < 0)
			{
				m_size = 0;
			}
			break;
		}
		else
		{
			pre = p;
			p = p->m_next;
		}
	}
}




template <class T>
void P2<T>::deleteList()
{
	Node *p = m_head;
	while (p!=NULL)
	{
		Node *pre = p;
		p = p->m_next;
		delete(pre);
	}
	m_head = NULL;
	m_size = 0;
}

template <class T>
bool P2<T>::isNull()
{
	if (m_head == NULL)
	{
		m_size = 0;
		return true;
	}
	return false;
}

template <class T>
void P2<T>::reverseList()
{
	/*
	链表反转
	没啥难度

	先到倒数第二个节点,并记录 tail节点
	然后将倒数第二个节点的下一个节点 的next指向倒数第二个节点
	
	倒数第二个下一个是倒数第一个,倒数第一个下一个指向倒数第二,实现逆序。

	然后将倒数第二个的next 置为空,执行断链操作
	再次循环查找定位到新链表倒数第二个。

	循环执行上述步骤
	结束时,指针停留在开头第一个节点,在执行一次上述操作,即可将第二个节点的下一个指向第一个。

	最后将原来的tail 赋值给head

	执行过程如下

	0->1->2->3->4
	0->1->2->3 ,   4->3
	0->1->2,    4->3->2
	0->1,    4->3->2->1
	4->3->2->1->0
	*/
	if (isNull())
	{
		return;
	}
	Node * p = m_head;

	Node* pPre = m_head;
	Node* tail = NULL;
	while (p->m_next != NULL)
	{
		pPre = p;
		p = p->m_next;
	}
	tail = p;

	while (pPre != m_head)
	{
		pPre->m_next->m_next = pPre;
		pPre-> m_next = NULL;
		p = m_head;
		pPre = m_head;
		while (p->m_next != NULL)
		{
			pPre = p;
			p = p->m_next;
		}
	}
	pPre->m_next->m_next = pPre;
	pPre->m_next = NULL;
	m_head = tail;

	printfList();
}

template <class T>
void P2<T>::createList(T v)
{
	if (isNull())
	{
		m_head = new Node(v);
		m_size = 1;
	}
}

template <class T>
void  P2<T>::printfList()
{
	Node *p = m_head;
	while (p != NULL)
	{
		cout << p->m_value << "->";
		//T需要重载输出符号
		p = p->m_next;
		
	}
	cout <<"表长:"<<m_size<< endl;
}

template <class T>
P2<T>::Node::Node():m_next(NULL)
{
}

template <class T>
P2<T>::Node::Node(T value) : m_value(value), m_next(NULL)
{
}

template <class T>
P2<T>::Node::~Node()
{
	cout<<"节点被销毁"<<endl;
}

template <class T>
T  P2<T>::getByIndex(int i)
{
	if (isNull() || i >= m_size)
	{
		return NULL;
	}
	Node*p = m_head;
	int index = 0;
	while (index < i)
	{
		p = p->m_next;
		index++;
	}
	return p->m_value;
}

int main(int argc, char * argv[])
{
	P2<int>* p = new P2<int>();
	p->createList(-1);
	p->insert(0);
	p->insert(1);
	p->insert(2);
	p->insert(3);
	p->insert(4);
	p->printfList();

	p->reverseList();
	/*cout << "第二个元素" << p->getByIndex(5) << endl;;

	p->printfList();
	p->remove(0);
	p->printfList();
	p->remove(1);
	p->printfList();
	p->remove(2);
	p->printfList();
	p->remove(-1);
	p->deleteList();
	p->printfList();*/

	cout << "第二个元素" << p->getByIndex(2) << endl;;
	system("pause");
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

zanglengyu

敲碗要饭

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

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

打赏作者

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

抵扣说明:

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

余额充值