一、测试链表程序
介绍如何创建,打印,删除链表程序。
#include<iostream>
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
ListNode* createLinkedList(int arr[], int n){
if( n == 0 ) return NULL;
ListNode* head = new ListNode(arr[0]);
ListNode* curNode = head;
for(int i = 1; i < n; i++){
curNode->next = new ListNode(arr[i]);
curNode = curNode->next;
}
return head;
}
void printLinkedList(ListNode* head){
ListNode* curNode = head;
while( curNode != NULL){
cout << curNode->val << " -> ";
curNode = curNode->next;
}
cout << "NULL" << endl;
}
void deleteLinkedList(ListNode* head){
ListNode* curNode = head;
while( curNode != NULL){
ListNode* delNode = curNode;
curNode = curNode->next;
delete delNode;
}
return;
}
class Solution{
public:
ListNode* reverseList(ListNode *head){
ListNode* pre = NULL;
ListNode* cur = head;
while( cur != NULL) {
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
};
int main() {
int arr[] = {1,2,3,4,5};
int n = sizeof(arr) / sizeof(int);
ListNode* head = createLinkedList (arr, n);
printLinkedList (head);
ListNode* head2 = Solution().reverseList (head);
printLinkedList (head2);
deleteLinkedList (head2);
return 0;
}
二、常见应用
1.设立链表的虚拟头结点
203. Remove Linked List Elements
Remove all elements from a linked list of integers that have value val.
Example:
Input: 1->2->6->3->4->5->6, val = 6
Output: 1->2->3->4->5
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummpNode = new ListNode(0);
dummpNode -> next = head;
ListNode* curNode = dummpNode;
while(curNode->next != NULL){
if(curNode->next -> val == val){
ListNode* delNode = curNode->next;
curNode->next = delNode->next;
delete delNode;
}else{
curNode = curNode->next;
}
}
return dummpNode -> next;
}
};
2.复杂的穿针引线
24. Swap Nodes in Pairs
Given a linked list, swap every two adjacent nodes and return its head.
Example:
Given1->2->3->4
, you should return the list as2->1->4->3
.
Note:
- Your algorithm should use only constant extra space.
- You may not modify the values in the list's nodes, only nodes itself may be changed.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummpyNode = new ListNode(0);
ListNode* p = dummpyNode;
dummpyNode->next = head;
while(p->next!=NULL && p->next->next!=NULL){
ListNode* node1 = p->next;
ListNode* node2 = node1->next;
p->next = node2;
node1->next = node2->next;
node2->next = node1;
p = node1;
}
return dummpyNode->next;
}
};
3.在链表中删除节点
237. Delete Node in a Linked List
Write a function to delete a node (except the tail) in a singly linked list, given only access to that node.
Given linked list -- head = [4,5,1,9], which looks like following:
4 -> 5 -> 1 -> 9
Example 1:
Input: head = [4,5,1,9], node = 5
Output: [4,1,9]
Explanation: You are given the second node with value 5, the linked list
should become 4 -> 1 -> 9 after calling your function.
Example 2:
Input: head = [4,5,1,9], node = 1
Output: [4,5,9]
Explanation: You are given the third node with value 1, the linked list
should become 4 -> 5 -> 9 after calling your function.
Note:
- The linked list will have at least two elements.
- All of the nodes' values will be unique.
- The given node will not be the tail and it will always be a valid node of the linked list.
- Do not return anything from your function.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void deleteNode(ListNode* node) {
ListNode* deleteNode = node->next;
node->val = node->next->val;
node->next = node->next->next;
delete deleteNode;
}
};
4.双指针
19. Remove Nth Node From End of List
Given a linked list, remove the n-th node from the end of list and return its head.
Example:
Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes 1->2->3->5.
Note:
Given n will always be valid.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummpyNode = new ListNode(0);
ListNode* node1 = dummpyNode;
dummpyNode->next = head;
ListNode* node2 = dummpyNode;
ListNode* pre = NULL;
for(int i=0; i<n-1&&node1!=NULL; i++){
node1 = node1->next;
cout << "node1->val:" << node1->val << endl;
}
while(node1 != NULL && node2 != NULL){
node1 = node1->next;
if(node1 != NULL){
pre = node2;
node2 = node2->next;
cout << "node2->val:" << node2->val << endl;
}
else{
pre->next = node2->next;
delete node2;
}
}
return dummpyNode->next;
}
};
三、剑指offer例子
1.输入一个链表,从尾到头打印链表每个节点的值。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
stack<int> s;
while(head != NULL){
s.push(head->val);
head = head->next;
}
vector<int> v;
while(s.size()!=0){
v.push_back(s.top());
s.pop();
}
return v;
}
};
2.输入一个链表,输出该链表中倒数第k个结点。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
ListNode* first = pListHead;
ListNode* second = pListHead;
if(k < 1) return NULL;
for(int i = 0; i < k-1 && first != NULL; i++){
first = first->next;
}
if(first == NULL) return NULL;
while(first->next != NULL){
first = first->next;
second = second->next;
}
return second;
}
};
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
ListNode* first = pListHead;
ListNode* second = pListHead;
if(k < 1) return NULL;
for(int i = 0; i < k - 1 && first != NULL;i++){
first = first -> next;
}
while(first != NULL){
first = first -> next;
if(first != NULL){
second = second -> next;
}else{
return second;
}
}
return NULL;
}
};
3.输入一个链表,反转链表后,输出新链表的表头。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
ListNode* curNode = pHead;
ListNode* pre = NULL;
ListNode* next = NULL;
while(curNode != NULL){
next =curNode->next;
curNode->next=pre;
pre = curNode;
curNode = next;
}
return pre;
}
};
4.输入两个链表,找出它们的第一个公共结点。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
stack<ListNode*> s1;
stack<ListNode*> s2;
while(pHead1 != NULL){
s1.push(pHead1);
pHead1 = pHead1->next;
}
while(pHead2 != NULL){
s2.push(pHead2);
pHead2 = pHead2->next;
}
ListNode* common = NULL;
while(s1.size()!=0 && s2.size()!=0){
if(s1.top()->val == s2.top()->val){
common = s1.top();
s1.pop();
s2.pop();
}else{
break;
}
}
return common;
}
};
5.在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
if(pHead == NULL) return NULL;
ListNode* dNode = new ListNode(pHead->val-1);
ListNode* preNode = dNode;
dNode->next = pHead;
ListNode* curNode = pHead;
while(curNode != NULL && curNode->next != NULL){
if(curNode->val == curNode->next->val){
curNode = curNode->next;
while(curNode != NULL && curNode->next != NULL && curNode->val == curNode->next->val){
curNode = curNode->next;
}
if(curNode != NULL){
preNode->next = curNode->next;
curNode = curNode->next;
}
}else{
preNode = preNode->next;
curNode = curNode->next;
}
}
return dNode->next;
}
};
6.输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1 == NULL) return pHead2;
if(pHead2 == NULL) return pHead1;
ListNode* merge = new ListNode(0);
ListNode* mergeList = merge;
while(pHead1!=NULL && pHead2!=NULL){
if(pHead1->val <= pHead2->val){
mergeList->next = pHead1;
mergeList = mergeList->next;
pHead1 = pHead1->next;
}
else{
mergeList->next = pHead2;
mergeList = mergeList->next;
pHead2 = pHead2->next;
}
}
if(pHead1){
mergeList->next = pHead1;
}
if(pHead2){
mergeList->next = pHead2;
}
return merge->next;
}
};
7.一个链表中包含环,请找出该链表的环的入口结点。
思路:
方法1:
使用hashmap
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
map<ListNode*, int> m;
while(pHead != NULL){
if(m.find(pHead) != m.end()) return pHead;
else {
m[pHead] = 1;
pHead = pHead->next;
}
}
return NULL;
}
};
方法2:
1)初始两个指针,均指向头结点。一个快指针,每次走两步;一个慢指针,每次走一步。
2)找出第一次相遇的结点;
3)一个指针指向头结点,一个指针指向第一次相遇的结点,两个指针每次向前移动一步,两个指针相遇的地方,即为该链表的环的入口结点。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
ListNode* slow = pHead;
ListNode* fast = pHead;
while(fast->next && fast->next->next){
slow = slow->next;
fast = fast->next->next;
if(slow == fast){
ListNode* p = pHead;
ListNode* q = slow;
while(p != q){
p = p->next;
q = q->next;
}
return p;
}
}
return NULL;
}
};
8.输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
TreeNode* Convert(TreeNode* pRootOfTree)
{
if(pRootOfTree == NULL) return NULL;
if(pRootOfTree != NULL && pRootOfTree->left == NULL && pRootOfTree->right== NULL)
return pRootOfTree;
TreeNode* left = Convert(pRootOfTree->left);
TreeNode* tmp = left;
while(tmp != NULL && tmp->right != NULL){
tmp = tmp->right;
}
if(tmp != NULL){
tmp->right = pRootOfTree;
pRootOfTree->left = tmp;
}
TreeNode* right = Convert(pRootOfTree->right);
TreeNode* tmp2 = right;
while(tmp2 != NULL && tmp2->left != NULL){
tmp2 = tmp2->left;
}
if(tmp2 != NULL){
pRootOfTree->right = tmp2;
tmp2->left = pRootOfTree;
}
return left != NULL ? left : pRootOfTree;
}
};
9.给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
/*
struct TreeLinkNode {
int val;
struct TreeLinkNode *left;
struct TreeLinkNode *right;
struct TreeLinkNode *next;
TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
}
};
*/
class Solution {
public:
TreeLinkNode* GetNext(TreeLinkNode* pNode)
{
if(pNode == NULL) return NULL;
if(pNode->right){
TreeLinkNode* next = pNode->right;
while(next->left){
next = next->left;
}
return next;
}
TreeLinkNode* parent = pNode->next;
while(parent != NULL){
if(parent->left == pNode) return parent;
pNode = parent;
parent = parent->next;
}
return parent;
}
};