主要来自于《剑指offer》,都是面试高频题
删除节点需要知道上一个节点的地址。就需要遍历,可以把问题转化为删除下一个节点,把下一个节点的值拷贝给本节点。 删除pdel就转化为删除pnext,不需要再从头遍历。时间复杂度为O(1).但是pdel为尾节点或者头节点需要另外的处理。
typedef struct SignalListNode { SignalListNode(const int& data = 0) :_data(data) ,_Pnext(NULL) {} SignalListNode *_Pnext; int _data; }Node; void DeleteNode(Node *&phead, Node *delNode) //删除节点 { if (NULL == phead || NULL == delNode) return; if (delNode->_Pnext != NULL) //非尾节点 { Node *pnext = delNode->_Pnext; delNode->_data = pnext->_data; delNode->_Pnext = pnext->_Pnext; delete pnext; pnext = NULL; } else if (phead == delNode) //头节点 { delete delNode; delNode = NULL; phead = NULL; } else //尾节点 { Node* ptemp = phead; while (ptemp -> _Pnext != delNode) { ptemp = ptemp->_Pnext; } ptemp->_Pnext = NULL; delete delNode; delNode = NULL; } }每次将节点入栈,然后出栈打印,栈和递归可以转化
void PrintTailtoHead_Nor(Node *phead) { stack<Node*> st; while (phead) { st.push(phead); phead = phead->_Pnext; } while (!st.empty()) { Node* pTemp = st.top(); cout << pTemp->_data << "->"; st.pop(); } cout << "NULL" << endl; } void PrintTailToHead(Node *phead) { if (phead) { PrintTailToHead(phead->_Pnext); cout << phead->_data << "->"; } }用快慢指针的方法,让快的先走K-1步,然后让快慢指针同时走,快指针到头时,慢指针到第倒数K个节点。
Node* FindKToTail(Node *phead, size_t k) //删除倒数第K个节点 { if (NULL == phead || k == 0) return NULL; Node *fast = phead; Node *slow = phead; while (--k) { if (fast->_Pnext == NULL) { cout << "已经到头了" << endl; return NULL; } fast = fast->_Pnext; } while (fast->_Pnext != NULL) { slow = slow->_Pnext; fast = fast->_Pnext; } return slow; }用ppre,pnode,pnext分别标记前一个,当前节点,后一个节点,在处理时需要注意顺序,和空指针的判断
Node* ResverLsit(Node *phead) //翻转链表 { if (NULL == phead || phead->_Pnext == NULL) return phead; Node* Tailhead = NULL; Node *pnode = phead; Node *ppre = NULL; while (pnode != NULL) { Node *pnext = pnode->_Pnext; if (NULL == pnext) Tailhead = pnode; pnode->_Pnext = ppre; ppre = pnode; pnode = pnext; } return Tailhead; }和第三题一样使用快慢指针的方法,先求出两个链表的长度,让长的先走它们的差值步。然后一起走,第一个相遇的节点就是两个链表的第一个交点。
size_t GetlenghtList(Node* phead) { if (NULL == phead) return 0; Node* pNode = phead; while (pNode->_Pnext != NULL) pNode = pNode->_Pnext; return (pNode - phead + 1); } Node* FindFirstFcous(Node* phead1, Node* phead2) { size_t len1 = GetlenghtList(phead1); size_t len2 = GetlenghtList(phead2); int len = len1 - len2; Node* shorthead = phead2; Node* longhead = phead1; if (len1 < len2) { shorthead = phead1; longhead = phead2; len = len2 - len1; } for (int i = 0; i < len; ++i) longhead = longhead->_Pnext; while ((longhead != NULL) && (shorthead != NULL) && (longhead != shorthead) ) { longhead = longhead->_Pnext; shorthead = shorthead->_Pnext; } return longhead; }一种是自己构建环,或者使用STL容器。
//约瑟夫环问题,0-n-1构成环,每次删除第m个元素,求最后剩下的数字 int JosephRing_1(int n, int m) { if (n < 1 || m < 1) return -1; Node* Ring = NULL; for (int i = 0; i < n; ++i) PushBack(Ring, i); Node* Tail = TailNode(Ring); Tail->_Pnext = Ring; Node* ppre = Tail; Node* pnode = Ring; while (ppre != pnode) { for (int j = 1; j < m; ++j) { ppre = ppre->_Pnext; pnode = pnode->_Pnext; } Node *pdel = pnode; ppre->_Pnext = pnode->_Pnext; pnode = pnode->_Pnext; delete pdel; } return pnode->_data; } int JosephRing_2(int n, int m) { if (n < 1 || m < 1) return -1; list<int> ring; for (int i = 0; i < n; ++i) ring.push_back(i); list<int>::iterator it = ring.begin(); while (ring.size() > 1) { for (int j = 1; j < m; ++j) { ++it; if (it == ring.end()) it = ring.begin(); } list<int>::iterator next = ++it; if (next == ring.end()) next = ring.begin(); --it; ring.erase(it); it = next; } return (*it); }和3,6题一样用到快慢指针,慢指针每次走一步,快指针每次走两步。如果带环,它们一定会在环内相遇。 入口点:先求出环的节点个数(走一圈),让快的先走一圈的个数步,然后两个同时走,会在入口点相遇。
//判断是否带环 Node *MeetingNode(Node* phead) { if (NULL == phead) return phead; Node *slow = phead->_Pnext; if (NULL == slow) return NULL; Node *fast = phead->_Pnext; while (fast != NULL && slow != NULL) { if (slow == fast) return fast; slow = slow->_Pnext; if (fast->_Pnext != NULL) fast = fast->_Pnext->_Pnext; else return NULL; } return NULL; } //求入口点 Node *GetEnterNode(Node *phead) { Node *meetNode = MeetingNode(phead); if (NULL == meetNode) return NULL; int ringnode = 1; Node *pnode = meetNode->_Pnext; while (pnode != meetNode) { ++ringnode; pnode = pnode->_Pnext; } Node* fast = phead; Node* slow = phead; for (int i = 0; i < ringnode; ++i) { fast = fast->_Pnext; } while (fast != slow) { fast = fast->_Pnext; slow = slow->_Pnext; } return slow; }