在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
源码:https://github.com/cjy513203427/C_Program_Base/tree/master/54.%E9%93%BE%E8%A1%A8 需要实现的方法 #pragma once #include"Node.h" #ifndef LIST_H #define LIST_H #include<iostream> using namespace std; class List { public: List();//构造函数 ~List();//析构函数 void ClearList();//清空链表 bool ListEmpty();//链表判空 int ListLength();//链表长度 bool GetElem(int i, Node *pNode);//获取指定索引的元素 int LocateElem(Node *pNode);//获取指定元素的索引 bool PriorElem(Node *pCurrentNode, Node *pPreNode);//获取前驱结点 bool NextElem(Node *pCurrentNode, Node *pNextNode);//获取后继结点 void ListTraverse();//遍历 bool ListInsert(int i,Node *pNode);//插入元素 bool ListDelete(int i, Node *pNode);//删除元素 bool ListInsertHead(Node *pNode);//插入在头结点后面 bool ListInsertTail(Node *pNode);//插入到链表最后 private: Node * m_pList; int m_iLength; }; #endif // !LIST_H 1.构造函数堆中为头结点m_pList申请内存 m_pList数据域置为0 指向地址为空,事实上这里声明了一个头结点,头结点没有后继结点并且数据域为空 长度置为0
List::List() { m_pList = new Node; m_pList->data = 0; m_pList->next = NULL; m_iLength = 0; } 2.析构函数调用清空链表方法 删除头结点并置空 List::~List() { ClearList(); delete m_pList; m_pList = NULL; } 3.清空链表声明一个Node*类型的指针指向m_pList的下一个结点,特别指明:m_pList是头结点,m_pList->next是头结点的指针域 判断currentNode是否为空,即判断m_pList的指针域是否为空,为空说明currentNode是尾结点,尾结点没有后继结点 currentNode不为空时,声明一个Node*类型的指针temp指向currentNode的下一个结点,也可以理解为temp接收currentNode的指针域值 删除当前的currentNode,再把temp保存的currentNode的指针域赋值回去 依次类推... 循环结束,再把尾结点指针域置空
清空链表和析构函数的区别:清空链表是将头结点之后的结点全部清空,析构函数是把头结点和之后的结点全部清空 void List::ClearList() { Node *currentNode = m_pList->next; while (currentNode != NULL) { Node *temp = currentNode->next; delete currentNode; currentNode = temp; } m_pList->next = NULL; } 4.链表判空与获取长度没什么好说的 bool List::ListEmpty() { return 0 == m_iLength ? true : false; } int List::ListLength() { return m_iLength; } 5.在头结点后面插入元素pNode指针作为参数传入 temp保存头结点的指针域,指向第一个结点 在堆中申请一个newNode指针的内存 没申请到内存返回错误 申请到内存,参数的数据域赋值给新结点数据域 头结点指向新结点 新结点指向原来头结点的下一个结点,这样链表就连接起来了
bool List::ListInsertHead(Node *pNode) { Node *temp = m_pList->next; Node *newNode = new Node; if (newNode == NULL) //判断申请的结点内存是否为空 { return false; } else { newNode->data = pNode->data; m_pList->next = newNode; newNode->next = temp; m_iLength++; return true; } } 6.在尾结点后面插入元素pNode指针作为参数传入 currentNode接收头结点 判断currentNode是否是尾结点,因为尾结点后继结点为空 循环到最后一个结点,此时currentNode->next=NULL 在堆中申请一个newNode的内存 没申请到内存返回错误 申请到内存 pNode的数据域赋值给newNode的数据域 新结点指针域置空 currentNode指向新结点 新结点指向空,这样链表就连接起来了,新结点成为了新的尾结点 链表长度++ 返回正确
bool List::ListInsertTail(Node *pNode) { Node *currentNode = m_pList; while (currentNode->next != NULL) { currentNode = currentNode->next; } Node *newNode = new Node; if (newNode == NULL) { return false; } else { newNode->data = pNode->data; newNode->next = NULL; currentNode->next = newNode; m_iLength++; return true; } } 7.插入元素判断参数i的合法性 i不能小于0,i不能大于链表长度,i等于链表长度代表可以尾元素后插入 currentNode保存头结点 声明newNode pNode数据域赋值给newNode数据域 新结点指向原来结点的下一个结点 原来的结点指向新结点
bool List::ListInsert(int i, Node *pNode) { if (i<0 || i>m_iLength) { return false; } Node *currentNode = m_pList; for (int k = 0; k < i; k++) { currentNode = currentNode->next; } Node *newNode = new Node; if (newNode == NULL) //判断申请的结点内存是否为空 { return false; } else { newNode->data = pNode->data; newNode->next = currentNode->next; currentNode->next = newNode; return true; } } 8.删除元素判断i是否合法,索引最大是m_iLength-1,和循环条件k<i对应 currentNode保存头指针 currentNodeBefore置空 currentNodeBefore指向currentNode的下一个结点的指针域,这样currentNode就可以被删除释放了 pNode数据域接收当前结点的数据域 删除当前结点并置空
bool List::ListDelete(int i, Node *pNode) { if (i<0 || i>=m_iLength) { return false; } Node *currentNode = m_pList; Node *currentNodeBefore = NULL; for (int k = 0; k <= i; k++) { currentNodeBefore = currentNode; currentNode = currentNode->next; } currentNodeBefore->next = currentNode->next; pNode->data = currentNode->data; delete currentNode; currentNode = NULL; m_iLength--; return true; } 9.获取指定索引的元素逻辑同删除元素 bool List::GetElem(int i, Node *pNode) { if (i<0 || i >= m_iLength) { return false; } Node *currentNode = m_pList; Node *currentNodeBefore = NULL; for (int k = 0; k <= i; k++) { currentNodeBefore = currentNode; currentNode = currentNode->next; } pNode->data = currentNode->data; return true; } 10.获取指定元素的索引currenNode保存头指针 只要currentNode的指针域/指向不为空,继续下去 如果参数的数据域等于currentNode的数据域,返回count,count就是索引 int List::LocateElem(Node *pNode) { Node *currentNode = m_pList; int count = 0; while (currentNode->next != NULL) { currentNode = currentNode->next; if (currentNode->data == pNode->data) { return count; } count++; } return -1; } 11.获取前驱结点currentNode保存头结点 中间变量tempNode置空 currentNode指针域不为空开始循环 tempNode保存当前结点 currentNode像后移一位 如果pCurrentNode的数据域等于当前结点的数据域 如果tempNode等于头结点,返回错误 将tempNode的数据域赋值给pPreNode的数据域,此时tempNode是保存的currentNode,currentNode是下一个的结点 所以currentNode->data==pCurrentNode->data是currentNode下一个结点的数据域和pCurrentNode比较 bool List::PriorElem(Node *pCurrentNode, Node *pPreNode) { Node *currentNode = m_pList; Node *tempNode = NULL; int count = 0; while (currentNode->next != NULL) { tempNode = currentNode; currentNode = currentNode->next; if (currentNode->data == pCurrentNode->data) { if (tempNode == m_pList) { return false; } pPreNode->data = tempNode->data; return true; } } return false; } 12.获取后继结点currentNode保存头指针 currentNode指针域不为空执行循环 currentNode一直向后移动 如果pCurrentNode的数据域等于currentNode的数据域 如果是尾结点,返回错误 再将当前结点指向的下一个结点的数据域赋值给pNextNode的数据域 bool List::NextElem(Node *pCurrentNode, Node *pNextNode) { Node *currentNode = m_pList; while (currentNode->next != NULL) { currentNode = currentNode->next; if (currentNode->data == pCurrentNode->data) { if (currentNode->next == NULL) { return false; } pNextNode->data = currentNode->next->data; return true; } } } 13.遍历currentNode保存头指针 currentNode只要不是尾结点一直遍历下去 currentNode后移,调用printNode()方法 void List::ListTraverse() { Node *currentNode = m_pList; while (currentNode->next != NULL) { currentNode = currentNode->next; currentNode->printNode(); } }
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论