单链表
单链表的设计与操作
#include<iostream> using namespace std; //单链表中每个节点的定义 template <typename T> struct Node { T data; //数据域,存放数据原元素 Node <T>* next; //指针域,指向下一个同类型(和本类型相同)节点。 }; //单链表的定义 template <typename T> class LinkList { public: LinkList(); //构造函数 ~LinkList(); //析构函数 public: bool ListInsert(int i, const T& e); //在第i个位置插入指定元素e bool ListDelete(int i); //删除第i个位置的元素 bool GetElem(int i, T& e); //获得第i个位置的元素值 int LocateElem(const T& e); //按元素值查找其在单链表中第一次出现的位置 void DispList(); //输出单链表中所有元素 int ListLength(); //获取单链表的长度 bool Empty(); //判断单链表是否为空 void ReverseList(); //翻转单链表 bool InsertPriorNode(Node<T> *pcurr, const T& e); //在pcurr的前面插入一个节点,节点值为e bool DeleteNode(Node<T>* pdel); private: Node<T>* m_head; //头指针(指向链表第一个节点的指针,如果链表有头节点,则指向头结点) int m_length; //单链表当前长读(当前有几个元素),为编写程序更方便和提高程序运行效率而引入 }; //通过构造函数对单链表进行初始化 template<typename T> LinkList<T>::LinkList() { m_head = new Node<T>; //先创建一个头结点 m_head->next = nullptr; m_length = 0; //头结点不计入单链表差长度 //如果不带头结点的单链表的初始化 // m_head = nullptr; // m_length = 0; } //在第i个位置(位置编号从1开始)插入指定元素 template<typename T> bool LinkList<T>::ListInsert(int i, const T& e) { //判断插入位置i是否合法,i的合法值应该是从1到m_length + 1之间 if(i < 1 || i > (m_length + 1)) { cout << "元素 " << e << " 插入的位置" << i << " 不合适,合法的位置是1到" << m_length + 1 << " 之间" <<endl; return false; } Node<T>* p_curr = m_head; //for循环用于找到第i - 1 个节点 for(int j = 0; j < (i - 1); ++j) //j从0开始,表示p_curr刚开始指向的是第0个节点(头结点) { p_curr = p_curr->next; //pcurr会找到当前要插入的位置,比如要在第二个位置插入,pcurr会指向第一个位置 } Node<T> *node = new Node<T>; //(1)创建一个新节点 node->data = e; node->next = p_curr->next; //(2)让新节点链上后续链表,因为pcurr->next指向后续的链表节点 p_curr->next = node; //(3)让当前位置链上新节点,因为node指向新节点 cout << "成功在位置为 " << i << " 处插入元素 " << e << endl; m_length++; //实际表长加一 return true; } //在第i个位置(位置编号从1开始)插入指定元素[不带头结点版本] // template<typename T> // bool LinkList<T>::ListInsert(int i, const T& e) // { // if(i < 1 || i > (m_length + 1)) // { // cout << "元素 " << e << " 插入的位置" << i << " 不合适,合法的位置是1到" << m_length + 1 << " 之间" <<endl; // return false; // } // if(i == 1) //插入到第一个位置与插入到其他位置不同,要单独处理 // { // Node<T> *node = new Node<T>; // node->data = e; // node->next = m_head; // m_head = node; //头指针质量新插入的第一个节点 // cout << "成功在位置为 " << i << " 处插入元素 " << e << endl; // m_lenth++; //实际表长+1 // return true; // } // //插入的不是第一个位置 // for(int j = 1; j < (i - 1); ++j) //j从0开始,表示p_curr刚开始指向的是第1个节点(头结点) // { // p_curr = p_curr->next; //pcurr会找到当前要插入的位置,比如要在第二个位置插入,pcurr会指向第一个位置 // } // Node<T> *node = new Node<T>; //(1)创建一个新节点 // node->data = e; // node->next = p_curr->next; // p_curr->next = node; // cout << "成功在位置为 " << i << " 处插入元素 " << e << endl; // m_length++; //实际表长加一 // return true; // } //在节点pcurr之前插入新节点,新节点数据域元素为e , template<typename T> bool LinkList<T>::InsertPriorNode(Node<T> *pcurr, const T& e) { if(pcurr == m_head) //只有一个头结点 { return false; } Node<T> *node = new Node<T>; node->next = pcurr->next; pcurr->next = node; node->data = pcurr->data; pcurr->data = e; m_length++; return true; } //删除第i个位置的元素 template<typename T> bool LinkList<T>::ListDelete(int i) { if(m_length < 1) { cout << "当前单链表为空,不能删除任何数据" <<endl; return false; } if(i < 1 || i > m_length) { cout << "删除位置 " << i << " 不合法,合法的位置是1到 " << m_length <<"之间" <<endl; return false; } Node<T> *p_curr = m_head; //for循环用于找到i - 1个节点 for(int j = 0; j < (i - 1); ++j) //j从0开始,表示p_curr刚开始指向的是0个节点(头结点) { p_curr = p_curr->next; //p_curr会找到当前要删除的位置所代表的节点的前一个节点的位置 } Node<T> *p_willdel = p_curr->next; //p_willdel指向带删除的节点 p_curr->next = p_willdel->next; //第 i - 1个节点的next指针指向了第 i + 1个节点 cout << "成功删除位置为 " << i << " 的元素,该元素的值为 " << p_willdel->data <<endl; m_length--; //实际表长-1 delete p_willdel; p_willdel->next = nullptr; return true; } template<typename T> bool LinkList<T>::DeleteNode(Node<T>* pdel) { //删除pdel所指向的节点,请自行添加相关代码 //1)把pdel后面一个节点的值赋值给pdel //2)删除pdel后面那个节点,间接的删除pdel //3)注意pdel本身就是最后一个节点的情况 if(pdel->next == nullptr) { delete pdel; } Node<T> *node = pdel->next; pdel->data = node->data; pdel->next = node->next; delete node; node = nullptr; m_length--; return false; } //获取第i个位置的元素值 template<typename T> bool LinkList<T>::GetElem(int i, T& e) { if(m_length < 1) { cout << "当前单链表为空,不能获取任何数据" <<endl; return false; } if(i < 1 || i > m_length) { cout << "获取位置 " << i << " 不合法,合法的位置是1到 " << m_length <<"之间" <<endl; return false; } Node<T>* p_curr = m_head; for(int j = 0; j < i; ++j) { p_curr = p_curr->next; } e = p_curr->data; cout << "成功获取 " << i << " 的元素,该元素的值为 " << e << endl; return true; } //按元素值查找其在单链表中第一次出现的位置 template<typename T> int LinkList<T>::LocateElem(const T& e) { Node<T>* p_curr = m_head; for(int i = 1; i <= m_length; ++i) { if((p_curr->next->data) == e) { cout << "值为 " << e << " 的元素在单链表中第一次出现的位置为 " << i <<endl; return i; } p_curr = p_curr->next; } cout << "值为 " << e << " 的元素在单链表中没有找到 " << endl; return -1; //返回-1表示查找失败 } //输出单链表中所有元素 template<typename T> void LinkList<T>::DispList() { Node<T> *p = m_head->next; while(p != nullptr) { cout << p->data << " "; p = p->next; } cout << endl; } //获取单链表长度 template<typename T> int LinkList<T>::ListLength() { return m_length; } //判断单链表是否为空 template<typename T> bool LinkList<T>::Empty() { if(m_head->next == nullptr) { return true; } return false; } //翻转单链表 template<typename T> void LinkList<T>::ReverseList() { if(m_length <= 1) { //如果顺序表中没有元素或者自由一个元素,那么不要做任何事情 cout << "不需要进行翻转" <<endl; return; } //至少由两个节点才会走到这里 Node<T> *pothersjd = m_head->next->next; //指向从第二个节点开始的后续节点 m_head->next->next = nullptr; //把第一个节点的指针域先置空 Node<T>* ptmp; while(pothersjd != nullptr) { //比如a1,a2,a3,a4共四个节点,第一次执行该循环时指向: ptmp = pothersjd; //ptmp -> a2; pothersjd = pothersjd->next; //pothersjd ->a3; ptmp->next = m_head->next; // a2 -> a1; m_head->next = ptmp; //head -> a2 -> a1 ->nullptr; } } //析构函数 template<typename T> LinkList<T>::~LinkList() { Node<T> *pnode = m_head->next; Node<T> *ptmp; while(pnode != nullptr) { ptmp = pnode; pnode = pnode->next; delete ptmp; } delete m_head; //释放头结点 m_head = nullptr; m_length = 0; } int main() { LinkList<int> slinkobj; slinkobj.ListInsert(1,12); slinkobj.ListInsert(1,24); slinkobj.ListInsert(3,48); slinkobj.ListInsert(2,100); //slinkobj.ListDelete(4); int temp = 0; slinkobj.GetElem(3,temp); cout << "get到的值为 " << temp << endl; slinkobj.LocateElem(100); slinkobj.DispList(); slinkobj.DispList(); slinkobj.ReverseList(); slinkobj.DispList(); return 0; } //额外学到的内容 //已知a2,要求往a2之前插入a5,简单方法是 //a)往a2后面插入a5 //b)把a2和a5数据域交换 //如果频繁的向单链表末尾插入新节点,可以考虑引入一个表尾指针。该指针在单链表为空时指向头结点。 //在单链表非空时要注意保持其指向最后一个节点。 //如何不使用前驱节点删除本节点 a1->a2->a3 只知道 a2 如何删除 a2 //a)把a3的值赋给 a2 (注意是值,而不是地址) //b)删除a3 //c)注意a2是最后一个元素的情况 //d) a) b)之后 a1-> a2[实际上,a2的值已经是a3了,只是地址没变,间接的删除了a2] ==> a1 -> a3 (最后的结果看成是这个)
欢迎大家指出博文中的错误哦。

浙公网安备 33010602011771号