一,逆置/反转单链表
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
(1)反转指针
ListNode* ReverseList(ListNode* head)
{
ListNode* cur == NULL;
ListNode* prev == NULL;
ListNode* next == NULL;
if(head == NULL || haed->_next == NULL)//考虑没有节点或者只有一个节点的情况
{
return;
}
cur = haed;
while(cur != NULL)
{
next = cur->_next;
cur->_next = prev;//指针反转
prev = cur;
cur = next;
}
if(cur == NULL)
{
head = prev;
return head;
}
}
(2)借用栈实现
void Reverse(Node *&haed)
{
if(head == NULL || head->_next == NULL)
{
return;
}
stack<Node*> s;
Node* cur = head;//入栈
while(cur->_next)
{
s.push(cur);
cur = cur->_next;
}
head = cur;
while(!s.empty())
{
Node* tmp = s.top();
cur->_next = tmp;
cur = tmp;
s.pop();
}
cur->_next = NULL;
}
二,查找单链表倒数第k个节点 (要求只能遍历一次链表)
输入一个链表,输出该链表中倒数第k个节点。
思考过程:
(1)看到这个题目很自然会想到先走到链表的尾部,再从尾部回溯k步,但是本题中的链表是单向链表,只有从前往后的指针而没有从后向前的指针,所以回溯法行不通。
(2)假设一共有n个节点,那么倒数第k个节点就是从头结点开始的第n-k+1个节点,但是n未知,所以需要我们先遍历一遍链表统计出总结点的个数n,第二次走n-k+1步就能找到倒数第k个节点,但此方法又不符合只能遍历一次的题目要求。
(3)既然不能遍历两次,我们可以换一种思路,定义快慢两个指针,快指针从链表的头指针开始向后走k-1步,慢指针保持不动;从第k步起,慢指针也开始从头指针与快指针同步走,当快指针到达链表的尾节点时,慢指针正好指向倒数第k个节点。
为了更加明了第三种思路,我来画图举例来示范一次。
主代码:
ListNode* Findktail(ListNode* Head,size_t k)
{
if(Head == NULL || k == 0)//排除异常情况
{
return NULL;
}
ListNode* fast == Head;//建立快慢指针
ListNode* slow == Head;
while(fast && --k)
{
fast = fast->_next;
}
if(fast == NULL)
{
return NULL;
}
if(k == 0)//当快指针走了k步
{
while(fast->_next != NULL)
{
fast = fast->_next;//慢指针从头跟着快指针同步走
slow = slow->_next;
}
}
return slow;
}
三,实现一个Add函数,让两个整数相加,但是不能使用+,-,*,/四则运算符
思路:求两数之和却不能使用四则运算,通过分析十进制数的相加机制我们可以联想到二进制数的位运算。
举个例子,5的二进制数101,17的二进制数为10001,我们试着把计算过程分为三步,第一步相加不进位。0+0为0,0+1与1+0均为1,因为不考虑进位所以在这里1+1也为0,可以观察到这个过程相当于异或运算。 第二步求得进位。对0+0,0+1,1+0而言都不会产生进位,只有1+1时,才会向前产生一个进位。此时可以认为两个数先做位与运算,然后再向左移动一位。 第三步把前两个步骤所得结果相加。
计算过程:
迭代法
int add(int num1,int num2)
{
while(num2 != 0)
{
int tmp1 = (num1^num2);
int tmp2 = (num1&num2)<<1;
num1 = tmp1;
num2 = tmp2;
}
return num1;
}
//递归
int add(int a,int b)
{
if(b == 0)
return a;
else
{
int sum = a^b;
int tmp = (a&b)<<1;
add(sum,tmp);
}
}
int main()
{
printf("%d\n",add(10,5));
return 0;
}