1.从尾到头打印单链表
//O(N^2)
void PrintTailToHead(SListNode* head)
{
SListNode* end = NULL;
while (end != head)
{
SListNode* cur = head;
while (cur->_next != end)
{
cur = cur->_next;
}
printf("%d ", cur->_data);
end = cur;
}
}
//方法二,递归划分为子问题解决
//每次打印当前链表的子链表,如子链表为空,则打印当前链表
//O(N)
void PrintTailToHeadR(SListNode* head)
{
if (head == NULL)
return;
PrintTailToHeadR(head->_next);
printf("%d ", head->_data);
}
- 删除⼀个⽆头单链表的⾮尾节点 (不能遍历)
void DelNode(SListNode* pos)
{
assert(pos && pos->_next);
//替换法删除
SListNode* next = pos->_next;
pos->_data = next->_data;
pos->_next = next->_next;
free(next);
}
3.在⽆头单链表的⼀个⾮头节点前插⼊⼀个节点 (不能遍历)
void InsertNode(SListNode* pos, DataType x)
{
assert(pos);
SListNode* tmp = BuySlistNode(pos->_data);
tmp->_next = pos->_next;
pos->_next = tmp;
pos->_data = x;
}
4.单链表实现约瑟夫环
SListNode* JosephCycle(SListNode* head, int k)
{
SListNode* tail = head,*cur =head; //tail尾
if (head == NULL) //链表为空
return NULL;
//构成环
while (tail->_next)
{
tail = tail->_next;
}
tail->_next = head;
while (cur->_next != cur) //环的结束
{
int count = k;
while (--count)
{
cur = cur->_next;
}
SListNode* next = cur->_next;
cur->_data = next->_data; //将next的值给cur
cur->_next = next->_next;//再将cur的_next指向next的_next
free(next);
}
return cur;
}
5.逆置/反转单链表
//方法一,三个指针
SListNode* ReverseList(SListNode* head)
{
if (head == NULL || head->_next == NULL)
{
return head;
}
SListNode* n1 = head, *n2 = n1->_next, *n3 = n2->_next;//这里要考虑指针为空
while (n2)
{
n2->_next = n1;
n1 = n2;
n2 = n3;
if (n3) //n3到最后为空
{
n3 = n3->_next;
}
}
head->_next = NULL;
head = n1;
return head;
}
//方法二,头插
SListNode* ReverseList2(SListNode* head)
{
SListNode* newhead = NULL;
SListNode* cur = head;
while (cur)
{
SListNode* tmp = cur;
cur = cur->_next;
//头插
tmp->_next = newhead;
newhead = tmp;
}
return newhead;
}
6.单链表排序-冒泡排序
void BubbleSortList(SListNode* head)
{
SListNode* cur, *next;
SListNode* tail = NULL;
if (head == NULL || head->_next == NULL)
{
return;
}
while (tail!=head->_next)
{
int flag = 0;
cur = head;
next = cur->_next;
while (next != tail)
{
if (cur->_data > next->_data)
{
DataType tmp = cur->_data;
cur->_data = next->_data;
next->_data = tmp;
flag = 1;
}
cur = cur->_next;
next = next->_next;
}
if (flag == 0)
{
break;
}
tail = cur;
}
}
7.合并两个有序链表,合并后依然有序
SListNode* MergeList(SListNode* list1,SListNode* list2)
{
SListNode* list, *tail;
if (list1 == NULL)
return list2;
if (list2 == NULL)
return list1;
if (list1->_data < list2->_data)
{
list = list1;
list1 = list1->_next;
}
else
{
list = list2;
list2 = list2->_next;
}
tail = list;
while (list1 && list2)
{
if (list1->_data < list2->_data)
{
tail->_next = list1;
list1 = list1->_next;
}
else
{
tail->_next = list2;
list2 = list2->_next;
}
tail = tail->_next;
}
if (list1)
tail->_next = list1;
if (list2)
tail->_next = list2;
return list;
}
8.查找单链表的中间节点
//用到的是快慢指针:定义两个指针,都指向链表的第一个成员
//然后快的指针每次走两步,慢的指针每次走一步
//当快指针指向的next为NULL即链表结点为奇数个的时候,或者,快指针快指针自身为空的时候停下,即链表元素为偶数个
//此时的慢指针走了s步,则快指针走了2s步,则此时慢指针所指向的结点为中间节点
SListNode* FindMidNode(SListNode* pHead)
{
SListNode* fast = NULL;
SListNode* slow = NULL;
fast = slow = pHead;
while (fast && fast->_next)
{
fast = fast->_next->_next;
slow = slow->_next;
}
return slow;
}
9.查找单链表的倒数第k个节点,要求只能遍历⼀次链表
SListNode* FindTailK(SListNode* pHead, int k)
{
if (pHead == NULL || k == 0) //一些异常情况
{
return NULL;
}
SListNode* fast = pHead;
SListNode* slow = pHead;
while (fast && --k) //这里一定要先自减,因为两个指针开始都指向头结点
{
fast = fast->_next;
}
if (fast == NULL) //即没找到的情况
{
return NULL;
}
if (k == 0)
{
while (fast->_next != NULL)
{
fast = fast->_next;
slow = slow->_next;
}
}
return slow;
}
10.删除链表的倒数第n个结点
Given a linked list.remove the n th node from the end of list and return its head.For 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.Tryto do this in one pass
// 题目 : 删除链表的倒数第n个结点
// 思路
// 1.找到链表的倒数第n个结点
// 2.删除倒数第n个结点,删除时需要对倒数第n个结点分情况 :
// 》>头结点 >> 非头结点
class Solution {
public:
ListNode *removeNthFromEnd(ListNode *head, int n) {
if (head == NULL || n <= 0)
return NULL;
ListNode* slow = head;
ListNode* fast = head;
while (--n && fast)
{
fast = fast->next;
}
ListNode* prev = NULL;
while (fast->next){
prev = slow;
fast = fast->next;
slow = slow->next;
}
if (slow == head){
head = head->next;
}
else{
prev->next = slow->next;
}
return head;
}
};
- 判断单链表是否带环?求环的⼊口点?
SListNode* IsCycle(SListNode* pHead)
{
SListNode* slow, * fast;
slow = fast = pHead;
while (fast && fast->_next)
{
slow = slow->_next;
fast = fast->_next->_next;
if (fast == slow)
{
return fast;
}
}
return NULL;
}
//入口点
SListNode* GetEntry(SListNode* pHead, SListNode* meet)
{
//L=NC-X(L是入环之前的长度,C是环的长度,X是如厚点到相遇点,N是常量)
//pHead是链表头,meet是相遇点
while (pHead != meet)
{
pHead = pHead->_next;
meet = meet->_next;
}
return meet;
}
12.判断两个链表是否相交,若相交,求交点。(假设链表不带环)
SListNode* GetCrossNode(SListNode* list1, SListNode* list2)
{
int len1 = 0, len2 = 0, gap = 0;
SListNode* cur1 = list1, *cur2 = list2;
SListNode* shortlist, *longlist;
while (cur1)
{
++len1;
cur1 = cur1->_next;
}
while (cur2)
{
++len2;
cur2 = cur2->_next;
}
longlist = list1;
shortlist = list2;
if (len1 < len2)
{
longlist = list2;
shortlist = list1;
}
gap = abs(len1 - len2);//abs是求绝对值
while (gap--)
longlist = longlist->_next;
while (longlist != shortlist) //相遇
{
longlist = longlist->_next;
shortlist = shortlist->_next;
}
return shortlist;
}
13.复杂链表的复制。
//⼀个链表的每个节点,有⼀个指向next指针指向下⼀个节点,
//还有⼀个random指针指向这个链表中的⼀个随机节点或者NULL,
//现在要求实现复制这个链表,返回复制后的新链表。
typedef struct RandomListNode
{
DataType _data;
struct RandomListNode* _next;
struct RandomListNode* _random;
struct RandomListNode* _label;
}RandomListNode;
//ComplexNode* Copy(ComplexNode* list);
RandomListNode* Clone(RandomListNode* pHead)
{
//if(pHead==NULL || pHead->next==NULL) return pHead; 当有一个结点的时候,不能直接返回啊,要复制~~
if (pHead == NULL) return NULL;
copy(pHead);
setNewNodeRandom(pHead);
RandomListNode *res = splice(pHead);
return res;
}
void copy(RandomListNode *pHead)
{
while (pHead != NULL)
{
RandomListNode *newnode = new RandomListNode(pHead->_label);
newnode->_next = pHead->_next;
//newnode->random=pHead->random; 新结点的random指针应先不设置
RandomListNode *__nextp = pHead->_next;//原来的__next结点
pHead->_next = newnode;//指向新结点
pHead = __nextp;
}
}
void setNewNodeRandom(RandomListNode *pHead)
{
while (pHead != NULL)
{
RandomListNode *_nextp = pHead->_next;
_nextp->_random = pHead->_random;
pHead = _nextp->_next;
}
}
RandomListNode* splice(RandomListNode *pHead)
{
RandomListNode *newHead = pHead->_next;
RandomListNode *head = newHead;
while (newHead->_next != NULL)
{
pHead->_next = newHead->_next;
pHead = newHead->_next;
newHead->_next = pHead->_next;
newHead = pHead->_next;
}
pHead->_next = NULL;
return head;
}
class Solution{
public:
RandomListNode* Clone(RandomListNode* pHead)
{
//参数检测:如果复杂链表不存在,无法赋值,直接返回
if (pHead == NULL)
return NULL;
//原链表每个节点后插入新节点
RandomListNode* pCur = pHead;
RandomListNode* pNewNode = NULL;
while (pCur)
{
pNewNode = new RandomListNode(pCur->lable);
assert(pNewNode);
pNewNode->next = pCur->next;
pCur->next = pNewNode;
pCur = pNewNode->next;
}
//给新节点的随机指针域赋值:新节点的随机指针域为旧结点随机域的next
pCur = pHead;
while (pCur)
{
pNewNode = pCur->next;
if (pCur->random == NULL)
{
pNewNode->random = NULL;
}
else
{
pNewNode->random = pCur->random->next;
}
pCur = pNewNode->next;
}
//将新节点从原链表中拆下来
RandomListNode* pNewNode = pHead->next;
pCur = pHead;
while (pCur->next)
{
pNewNode = pCur->next;
pCur->next = pNewNode->next;
pCur = pNewNode;
}
return pNewNode;
}
};
14.删除链表中重复的结点
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,
重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
if (pHead == NULL) {
return NULL;
}
ListNode* pNode = NULL;
ListNode* node = pHead;
while (node != NULL) {
if (node->next != NULL && node->val == node->next->val) {
int value = node->val;
while (node->next != NULL && node->next->val == value) {
node = node->next;
}
if (pNode == NULL) {
pHead = node->next;
}
else {
pNode->next = node->next;
}
}
else {
pNode = node;
}
node = node->next;
}
return pHead;
}
};
15.输入一颗二叉树,将该二叉搜索树转换成一个排序的双向链表,要求不能创建新节点只能调整树中节点指针的指向
class Solution{
public:
TreeNode* Convert(TreeNode* pRootOfTree)
{
//参数检测
if (pRootOfTree == NULL)
{
return NULL;
}
//查找链表的头,即二叉搜索树中最左边的结点
TreeNode* pHead = pRootOfTree;
while (pHead->left)
{
pHead = pHead->left;
}
//使用中序线索化的思想进行转换
TreeNode* pPrev = NULL;
_BSTreeToDList(pRootOfTree, pPrev);
return pHead;
}
void _BSTreeToDList(TreeNode* pRoot, TreeNode*& pPrev)
{
if (pRoot == NULL)
return;
//将当前结点的左子树转化为排序的双向链表
_BSTreeToDList(pRoot->left, pPrev);
//调整当前结点左指针域的指向,让其指向中序遍历结果中的前驱结点
pRoot->left = pPrev;
if (pPrev)
{
pPrev->right = pRoot;
}
//用pPrev来标记最近修改过的结点,因为需要将pPrev的改变结果带出去,因此pPrev的类型给成一级指针的引用类型,此处给二级指针也可以
pPrev = pRoot;
//调整当前结点右指针域的指向,让其指向中序遍历结果中的前驱结点
_BSTreeToDList(pRoot->right, pPrev);
}
};
16.输入两个链表,找出他们的第一个公共结点(链表相交)
class Solution {
public:
ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2) {
//参数检测,如果有一个链表尾空,都不可能有交点
if (NULL == pHead1 || NULL == pHead2)
return NULL;
/*
//此题为链表相交问题,链表相交时有两种情况:v型和Y型
//通关现察发现,让长的链表先走两个镇表插入步,然后两个链表同时向后走,相等的结点即为第一个结点
*/
int gap = Size(pHead1) - Size(pHead2);
ListNode* pL1 = pHead1;
ListNode* pL2 = pHead2;
//让长的链表先向后走两个链表差值步
if (gap > 0)
{
while (gap--)
{
pL1 = pL1->next;
}
}
else
{
while (gap++)
{
pL2 = pL2->next;
}
}
//两个链表同时向后走
while (pL1&& pL2)
{
if (pL1 == pL2)
return pL1;
pL1 = pL1->next;
pL2 = pL2->next;
}
//两个链表不想交
return NULL;
}
//辅助方法:获取链表中结点的个数
size_t Size(ListNode* pHead)
{
ListNode* pCur = pHead;
size_t count = 0;
while (pCur)
{
++count;
pCur = pCur->next;
}
return count;
}
};
17.一个链表中包含环,请找出该链表的环的入口结点(带环问题)
class Solution{
public:
ListNode* EntryNodeOfLoop(ListNode* pHead){
//参数检测 : 如果链表为空,直接返回
if (NULL == pHead)
return NULL;
//检测链表是否带环
//给两个指针,一个走一步,一个走两步,如果两个指针相遇,则链表带环
ListNode* pFast = pHead;
ListNode* pSlow = pHead;
while (pFast && pFast->next){
pSlow = pSlow->next;
pFast =pFast->next->next;
if (pSlow == pFast)
break;
}
//如果链表带环,则一定在环内相遇,pF ast或者pF ast的next - 定不为空
if (NULL == pFast || NULL == pFast->next)
return NULL;
//链表带环,找入口点
/*
pH 1
|
|
PE 2
/ \
/ \
3 7
| |
| |
4 6
\ /
\ /
5
PM
假设判环是快慢指针在5结点处相遇,设相遇点为PM .环入口点为pE, 链表头结点为pH
假设环的长度为R,从pH到pE的长度为L,从PE到pM的距离为X,则从pM到PE的距离为R - X
在判环时:
慢指针所在路径:L+ x(注意:慢指针进环后,快指针肯定在一圈之内追上慢指针)
快指针所走路径: L+ X + nR(注意:在慢指针进入环后 ,快指针可能已经在环内转了n圈)
因为快指针速度为慢指针的2倍,因此
2*(L+X)=L+X+nR
化简:L=nR-X
取极值:假设n=1,此时L=R-X
结论:环的入口点-->给两个指针,一个从链表头部开始,一个从相遇点位置开始,两个指针顺着链表的方向同时走
当两个指针相遇时,相遇点即为入口点
*/
ListNode* pCur = pHead;
ListNode* pM = pFast; // pFast即为判环时的相遇点
while (pcurIe pM){
pCur= pCur->next;
pM=pM->next;
}
return pCur;
}
};
18.Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST.
//给出一个单链表,结点是按元素递增的顺序排序,把链表转换成高度平衡的二叉搜索树
class Solution {
public:
TreeNode *sortedListToBST(ListNode *head) {
if (head == NULL)
{
return NULL;
}
if (head->next == NULL)
{
return new TreeNode(head->val);
}
ListNode* mid = head;
ListNode* end = head;
ListNode* premid = NULL;
while (end != NULL && end->next != NULL)
{
premid = mid;
mid = mid->next;
end = end->next->next;
}
TreeNode* root = new TreeNode(mid->val);
premid->next = NULL;
root->left = sortedListToBST(head);
root->right = sortedListToBST(mid->next);
return root;
}
};
19.Given a singly linked listL : LO→L1→…→Ln-1→Ln,
reorder it to : LO - →Ln→L1→Ln-1→L2→Ln - 2 + ..
You must do this in - place without altering the nodes’values.
For example,
Given{ 1, 2, 3, 4), reorder it to{ 1, 4, 2, 3 }.
//分析 :
//链表 : L0-->1-->2--->L3--->L4--->L5--->L6--->NULL
// L0--->L6--->L1--->L5--->L2--->L4--->L3--->NULL
// 从结果来看,此题相当于是将链表后半部分逆序.然后插入到前半部分的每个结点后
//方法一
#include <vector>
class Solution{
public:
void reorderlist(ListNode *head){
//参数检测:如果是空链表,直接返回
if (NULL == head)
return;
//将链表每个结点的地址保存到vector中
std::vector<ListNode*> v;
ListNode* pCur = head;
while (pCur)
{
v.push_back(pCur);
pCur = pCur->next;
}
//left从左边开始 right从右侧开始
//先改变left标记位置结点的指向,让其next指向right标记结点,left超后走
//再改变right标记位置结点的指针,让其next指向left标记结点,right超前走
//直到left与right相遇,更新完毕
//出了循环,中间位置结点刚好成新链表的最后一个节点,将其next位置NULL
int left = 0, right = v.size() - 1;
while (left < right)
{
v[left++]->next = v[right];
v[right--]->next = v[left];
}
v[left]->next = NULL;
}
};
//说明: 此方法非常简单,但是其时间复杂度为0(N), 空间复杂度为 : O(N)
//方法二 :
class Solution{
public :
void reorderlist(ListNode *head){
// 参数检测:如果是空链表或者链表中只有一 个节点,直接返回
if (NULL == head || NULL == head->next)
return;
//找到链表的中间结点
ListNode* pFast = head;
ListNode* pSlow = head;
while (pFast && pFast->next)
{
pFast = pFast->next->next;
pSlow = pS1ow->next;
}
//从中间结点开始,将链表分成两个链表
ListNode* pCur1 = head;
ListNode* pCur2 = pSlow->next;
pSlow->next = NULL;
//对链表的后半部分进行逆置
pCur2 = ReverseList(pCur2);
//将第二个链表中每个结点依次插入到第一 个链表每一 个结点后
ListNode* pTailNode = pCur1;
pCur1 = pCur1->next;
while (pCur1 && pCur2)
{
//将第二个链表中结点尾插到新链表中
pTailNode->next = pCur2;
pTailNode = pCur2;
pCur2 = pCur2->next;
//将第一个链表中结点尾插到新链表中
pTailNode->next = pCur1;
pTailNode = pCur1;
pCur1 = pCur1->next;
}
//将剩余结点连接到新链表的末尾
if (pCur1)
pTailNode->next = pCur1;
else
pTailNode->next = pCur2;
}
private:
//单链表逆置
ListNode* Reverselist(ListNode* pHead)
{
ListNode* pNewHead = NULL;
ListNode* pCur = pHead;
ListNode* pCurNext = NULL;
while (pCur)
{
pCurNext = pCur->next;
pCur->next = pNewHead;
pNewHead = pCur;
pCur = pCurNext;
}
return pNewHead;
}
};
20.Sort a linked list in O(n log n) time using constant space complexity.
//使用快速排序原理对链表进行排序
class Solution{
public:
ListNode *sortList(ListNode *head) {
_sortList(head, NULL);
return head;
private:
ListNode *_sortList(ListNode* pHead, ListNode* pTail)
//链表尾空,或者链表中只剩余一个节点,不用排序
if (pTail == pHead || pHead->next == pTail)
return pHead;
//通过_Pation()方法,将链表按照基准值分割成前后两部分
ListNode* pMiddle = _Pation(pHead, pTail);
//递归排链表的左半部分
_sortlist(pHead, pMiddle);
// 递归排链表的右半部分
sortList(pMiddle->next, pTail);
return pHead;
}
//取链pHead中元素作カ基准值將序列分割成比基准値小的左部分和比基值大的右半部分
//采用前后指针版本的快排分割数据原理
ListNode* _Pation(ListNode pHead, ListNode* pTail)
{
ListNode* pPrecur = pHead;
ListNode* pCur = pHead->next;
int key = pHead->val;
while (pCur != pTail)
{
if (pCur->val < key)
{
pPreCur = pPrecur->pnext;
if (pPrecur != pCur)
Swap(pCur->val, pPreCur->val);
}
pCur = pCur->next;
}
if (pPreCur != pHead)
swap(pPreCu->val, pHead->val);
//返回基准値所在結点
return pPrecur;
}
};
21.Given a inked ist and a value x partition it such that all nodes less than x come before nodes 8
than or equalto X.
You should preserve the original relative order of the nodes in each of the two partitions.
For example,
Given1->4->3->2->5->2andx = 3,
return1->2->2->4->3->5.
//题目 : 按照指定值x将链表分割成两部分.前面全部比x小,后面结点大于等于x
//从输出结果可以看出 : 小的结点保持在原链表中小于的次序
// 大于等于的结点保持在原链表中的大于等于次序
//
//初次看到此题.感觉与快速排序分割算法类似,但是快排的分割不稳定,而本题需要稳定的算法。
//思路 :
//创建两个新链表minList和maxlist
//将小于的结点尾插到minList中,将大于等于的结点尾插到maxlist中
//将maxList链表链接在minList末尾
class Solution{
public:
ListNode *partition(ListNode *head, int x){
//参数检测:空链表或者链表中只有一一个节点,直接返回
if(NULL = head)
return head;
ListNode* minList = NULL;
ListNode* minListTail = NULL;
ListNode* maxList = NULL;
ListNode* maxListTail = NULL;
ListNode* pCur = head;
//将原链表中结点分离开
//小于x的结点尾插到minList中,大于等于x的结点尾插到maxlist中
while (pCur)
{
if (pCur->val < x)
{
if (minList)
minListTail->next = pCur;
else
minList = pCur;
minListTail = pCur;
}
else
{
if (maxList)
maxListTail->next = pCur;
else
maxList = pCur;
maxListTail = pCur;
}
pCur = pCur->next;
}
//将两个链表最后一个节点的next指针域置空
if(maxListTail)
maxListTail->next = NULL;
if (minListTail)
minListTail->next = NULL;
//将maxList链表链接在minList末尾
if (minListTail)
{
minListTail->next=maxList;
return minList;
}
return maxList;
}
};
22.Given a list, rotate the list to the right by k places, where k is non - negative.
For example :
Given1->2->3->4->5->NULL and k = 2,
return4->5->1->2->3->NULL
// 链表的循环移位
// 思路
// 1.先将链表构成一个环,并记录链表中结点的个数count
// 2.确定k的值(因为k可能大于链表中结点的个数.如果大于,用k对链表中结点的个数取模k=k%count)
// 3.移动结点
//即在链表中找到移动之后新链表的头,右移k个结点.反过来想就是让一个指针从链表的头部往后走count-k
// 步,pCur位置即为移动之后新链表的头。
// 4.将环断开
#include <assert.h>
class Solution{
public:
ListNode *rotateRight(ListNode *head, int k){
//参数检测
if (NULL == head)
return MULL;
//题目说明: k为非负数,此处对k断言下
assert(k >= 0);
//获取链表中结点的个数,顺表记录链表的尾结点
int count = 0;
ListNode* pCur = head;
ListNode* pPreCur = NULL;
while (pCur)
{
count++;
pPreCur = pCur;
pCur = pCur->next;
}
//将链表构成环
pPreCur->next = head;
//如果k大于等于链表中结点的个数,将其对链表长度取模
k %= count;
k = count - k;
pCur = head;
while (k--)
{
pPreCur = pCur;
pCur = pCur->next;
}
pPreCur->next = NULL;
return pCur;
}
};