数据结构域算法————链表

#include 

// 
// 链表的数据结构
// 1. 链表是由每一个节点连接起来的.
struct Node {
	int		nData; // 数据域
	Node*	pNext; // 指针域,用于保存下一个节点的首地址
};

class List {
	// 记录当前链表的节点个数
	int m_nCount=0;
	// 用于保存链表的头节点的地址
	Node* m_pHead = nullptr;
public:
	/*!
	 * 函数名 : insert
	 * 功  能 : 将元素nData插入到链表的第nIndex位置
	 * 参  数 : int nIndex 插入到的下标
	 * 参  数 : int nData 要插入的数据
	 * 返回值 :  bool
	 */
	bool insert(int nIndex, int nData)
	{
		// 1. 检查插入位置是否错误.
		if (nIndex <0 || nIndex>m_nCount) {
			return false;
		}
		// 2. 在堆空间中申请内存来保存新的节点
		Node* pNew = new Node;
		// 2.1 将要插入到链表中的数据保存在新节点.
		pNew->nData = nData;
		// 3. 在链表中找到插入位置的前一个节点.
		// 3.1 如果插入到的是第0个位置.那么需要将
		//     新节点的首地址记录在m_pHead指针中.
		if (nIndex == 0) {
			pNew->pNext = m_pHead;
			m_pHead = pNew;
		}
		else {
			// 循环遍历到插入位置的前一个节点.
			Node* pPre = m_pHead;
			for (int i = 1; i < nIndex; ++i) {
				pPre = pPre->pNext;
			}
			// 4. 将前一个节点的pNext字段保存到新节点的pNext字段
			//	  这样就可以让新节点记录下一个节点
			pNew->pNext = pPre->pNext;
			// 5. 将新节点的首地址保存到前一个节点的pNext字段
			//    这样通过前一个节点就能找到新的节点.
			pPre->pNext = pNew;
		}
		// 6. 增加节点个数.
		++m_nCount;
	}

	/*!
	 * 函数名 : remove
	 * 功  能 : 从链表中删除下标为nIndex的元素
	 * 参  数 : int nIndex 要删除的元素所在的下标
	 * 返回值 :  void
	 */
	void remove(int nIndex)
	{
		// 1. 判断下标是否正确
		if (nIndex < 0 || nIndex >= m_nCount) {
			return;
		}
		// 2. 找到要删除的元素的前一个节点
		// 2.1 如果删除的是第0个节点. 这个节点的首地址
		//     是保存在m_pHead头节点指针中.
		//     因此, 直接操作头节点指针.
		if (nIndex == 0) {
			// m_pHead->pNext记录的是被删除节点的下一个
			// 节点的首地址
			// 现在将下一个节点作为新的头节点:将节点的地址
			// 记录在头节点指针中.
			Node* temp = m_pHead;
			m_pHead = m_pHead->pNext;
			delete temp;
		}
		else {
			Node* pPreNode = m_pHead;
			for (int i = 1; i < nIndex; ++i) {
				pPreNode = pPreNode->pNext;
			}
			// 3. 通过前一个节点的pNext字段找到被删除节点
			//	  的首地址
			Node* pRemoveNode = pPreNode->pNext;
			// 4. 再通过被删除节点的pNext字段,得到被删除
			//    节点的下一个节点的首地址
			Node* pNextNode = pRemoveNode->pNext;
			// 5. 将被删除节点的下一个节点的首地址保存到
			//    被删除节点的前一个节点的pNext字段.
			pPreNode->pNext = pNextNode;
			// 6. 释放掉被删除节点的内存空间
			delete pRemoveNode;
		}
		// 7. 递减当前节点个数
		--m_nCount;
	}

	/*!
	 * 函数名 : find
	 * 功  能 : 在链表中查找元素
	 * 参  数 : int nData 被查找的元素
	 * 返回值 : int 元素在链表中的下标,找不到了就返回-1
	 */
	int find(int nData) {
		Node* pNode = m_pHead;
		int nIndex = 0;
		while (pNode != nullptr) {
			// 判断当前遍历到的节点保存的数据
			// 是否是要查找的数据
			if (pNode->nData == nData) {
				// 如果是,就返回下标
				return nIndex;
			}
			// 递增下标,用于记录,当前遍历到了第几个元素
			++nIndex;
			// 找到下一个节点
			pNode = pNode->pNext;
		}
		return -1;
	}

	/*!
	 * 函数名 : at
	 * 功  能 : 获取指定下标的元素的数据域的引用.
	 * 参  数 : int nIndex 元素所在的下标
	 * 返回值 :  int& 返回数据的引用.这样就可以在函数外部修改节点的数据了
	 */
	int& at(int nIndex) {
		if (nIndex < 0 || nIndex >= m_nCount) {
			throw std::exception("下标越界");
		}
		// 遍历到指定下标处的节点
		Node* pNode = m_pHead;
		for (int i = 0; i < nIndex; ++i) {
			pNode = pNode->pNext;
		}
		// 返回节点的引用(返回值是int&引用类型)
		return pNode->nData;
	}

	/*!
	 * 函数名 : push_back
	 * 功  能 : 将数据插入到链表最后一个位置
	 * 参  数 : int nData
	 * 返回值 :  void
	 */
	void push_back(int nData) {
		insert(m_nCount, nData);
	}

	/*!
	 * 函数名 : pop_back
	 * 功  能 : 将最后一个元素的值输出到*pData,然后删除
	 * 参  数 : int * pData
	 * 返回值 :  void
	 */
	void pop_back(int* pData) {
		if (m_nCount) {
			// 先获取最后一个元素的值,并保存到
			// 指针指向的内存中
			*pData = at(m_nCount - 1);
			// 删除该元素
			remove(m_nCount - 1);
		}
	}

	/*!
	 * 函数名 : push_front
	 * 功  能 : 将数据插入到链表的最前面
	 * 参  数 : int nData
	 * 返回值 :  void
	 */
	void push_front(int nData) {
		insert(0, nData);
	}

	/*!
	 * 函数名 : pop_front
	 * 功  能 : 删除链表最前面的数据, 删除前,将值输出到*pData
	 * 参  数 : int * pData
	 * 返回值 :  void
	 */
	void pop_front(int * pData) {
		if (m_nCount) {
			// 先获取最后一个元素的值,并保存到
			// 指针指向的内存中
			*pData = at( 0 );
			// 删除该元素
			remove( 0 );
		}
	}

	/*!
	 * 函数名 : print
	 * 功  能 : 打印链表中的所有元素
	 * 返回值 :  void
	 */
	void print() {
		Node* pNode = m_pHead;
		printf("[");
		while (pNode != nullptr) {
			// 打印节点的数据域
			printf("%d,", pNode->nData);
			// 找到下一个节点
			pNode = pNode->pNext;
		}
		printf("\b]\n");
	}
};


int main(){
	List l;
	printf("测试插入功能:\n");
	l.insert(0, 10);
	l.insert(0, 9);
	l.insert(2, 12);
	l.insert(1, 11);
	l.print();

	// 修改链表的下标为2的项
	printf("\n测试修改功能:\n");
	int& rEle = l.at(2);
	printf("下标为2项的值:%d\n", rEle);
	rEle = 100;
	printf("下标为2项的值:%d\n", rEle);

	printf("\n测试查找功能:\n");
	int nIndex = l.find(12);
	printf("元素12在链表中的第%d项\n", nIndex);

	printf("\n测试删除功能:\n");
	// 删除元素9
	// 1. 先通过find查找到元素9的下标
	// 2. 在通过删除函数删除指定下标的元素
	l.remove(l.find(9));

	l.remove(3);// 9- 11 - 10 -12
	l.print();

	l.remove(1);
	l.print();

	l.remove(0);
	l.print();

	// 模拟栈的操作:
	printf("\n模拟栈操作:\n");
	int nData = 0;
	l.push_back(10);
	l.push_back(9);
	l.push_back(8);
	l.push_back(7);
	l.print();

	l.pop_back(&nData);
	l.print();
	l.pop_back(&nData);
	l.print();
	l.pop_back(&nData);
	l.print();
	l.pop_back(&nData);
	l.print();

	// 模拟队列的操作
	printf("\n模拟队列操作:\n");
	l.push_back(100);
	l.push_back(101);
	l.push_back(102);
	l.push_back(103);
	l.pop_front(&nData);
	l.print();
	l.pop_front(&nData);
	l.print();
	l.pop_front(&nData);
	l.print();
	l.pop_front(&nData);
	l.print();
}

你可能感兴趣的:(数据结构域算法————链表)