17_7_14:逆置单链表+查找单链表的倒数第K个节点+非常规方法实现Add函数
来源:互联网 发布:巴哥犬价格知乎 编辑:程序博客网 时间:2024/06/07 06:52
1.【基础题】–逆置/反转单链表+查找单链表的倒数第k个节点,要求只能遍历一次链表
2.【附加题】–实现一个Add函数,让两个数相加,但是不能使用+、-、*、/等四则运算符。ps:也不能用++、–等等
**
1,基础题:
**
/*注:本次代码处理的是不带环的单链表*/#include <stdio.h>#include <stdlib.h>typedef struct ListNode{ int _val; struct ListNode* _pNext;}Node, *PNode;/*逆置 / 反转单链表:思路:可以利用三个指针来标记三个连续节点。1,将头结点的指针置为NULL2,将头结点后面的_pNext在循环中改变指向: 第一个指针不变,逆置中间指针的指向,保留第三个指针的指向,作为往后遍历链表的路径。 这样遍历链表,每次逆置中间节点的指向,通过第三个节点往后遍历,将三个节点指针整体往后移一个节点。 最终改变整个链表。通过以上思路,将链表分为三种情况:1,链表为空。2,链表只含有1个节点。3,链表有2个及以上节点。*/PNode ReverseList(PNode pHead){ PNode pPre = NULL; //第一个指针,指向连续节点中的第一个节点,最终成为新的头结点指针。 PNode pCur = NULL; //第二个指针,指向连续节点中的第二个节点,修改_pNext指向的指针。 PNode pTail = NULL; //第三个指针,指向连续节点中的第三个节点,保持与单链表连接的指针。 //链表为空的情况 if (NULL == pHead) return NULL; //链表只有一个节点的情况 if (NULL == pHead->_pNext) return pHead; //链表有2个及以上节点的情况 pPre = pHead; pCur = pPre->_pNext; pTail = pCur->_pNext; //处理pHead的_pNext指向 pHead->_pNext = NULL; //处理头结点之后的节点_pNext指向 while (pCur) { pCur->_pNext = pPre; pPre = pCur; pCur = pTail; if (pTail) //当该条件不成立时,表示pTail为NULL,下一次循环中pCur也NULL,将会跳出循环。 pTail = pTail->_pNext; } //此时pPre指向的是新的头结点 return pPre;}/*查找单链表的倒数第k个节点,要求只能遍历一次链表:思路:通过两个指针,一个前指针,一个后指针。1,两个指针,初始都是指向单链表的头结点。2,前指针先走K步。然后和后指针一起往后走。3,直到前指针指向NULL。注意,根据K的大小与单链表中元素个数的比较。可以分为:1,K的值大于单链表中元素个数。2,K的值小于等于单链表中元素个数。3,需要注意K为0的情况但是,链表中元素个数,必须通过遍历之后,才能知晓。所以,可以在前指针往后走K步的过程中(即K-1步及之前),同时判断前指针是否为NULL。如果前指针为NULL,表示单链表元素个数小于K。否则大于等于K。*/PNode Find_the_penultimate_K_node(PNode pHead, size_t k){ //使用左、右来标识前、后指针。pHead是否为NULL,不影响程序逻辑。 PNode pLeft = pHead; PNode pRigth = pHead; if (!k) return NULL; //前指针先往后走K步 while (k && pLeft) { pLeft = pLeft->_pNext; --k; } if (k) //k>0,pLeft=NULL.表示元素个数小于K return NULL; //走到这一步,说明单链表元素个数大于等于K,然后,前后指针开始一起往后走。直到前指针为NULL while (pLeft) { pLeft = pLeft->_pNext; pRigth = pRigth->_pNext; } //返回倒数第K个节点指针。 return pRigth;}//打印单链表void PrintList(PNode pHead){ while (pHead) { printf("%d->", pHead->_val); pHead = pHead->_pNext; } printf("NULL\n");}int main(){ int i = 0; Node node[10] = {0}; //建立10个node用来做实验 PNode pHead = &node[0]; //指向头结点 PNode pTemp = NULL; //指向倒数第K个节点 int k = 0; //给node赋值 for (; i < 10; ++i) node[i]._val = i; //构成一个单链表 for (i = 0; i < 9; ++i) node[i]._pNext = &node[i + 1]; node[9]._pNext = NULL; //注意,最后一个节点指向NULL PrintList(pHead); //打印旧的单链表 pTemp = Find_the_penultimate_K_node(pHead, 5); //寻找倒数第K个节点 printf("Find the penultimate K node is %d\n", pTemp->_val); pHead = ReverseList(pHead); //逆置单链表 PrintList(pHead); //打印新的单链表 system("pause"); return 0;}
**
2,附加题
**
(1)利用两数相加,从后往前进位的思想
思路:
1,0和1可以表示某一位上的数值。(对于sum来说)
2,0和1还可以表示两种状态,即序列中某一位的状态(不需要进位与需要进位)。(对于carry来说)
3,a^b运算的结果是:二进制序列,不进位,只相加的结果sum。(0^0=0,1^0=1,1^1=0)
4,a&b运算,然后左移一位,的结果是:二进制序列中哪些位是需要进位carry。(0&0=0,1&0=0,1&1=1,然后将序列左移1位)
5,通过sum与carry带入3,4中的a与b,可以从后往前不断进位,直到carry为0,表示没有需要进位的位。
/*//递归版本int Add_2(int a, int b){ if (0==b) return a; else { int sum = a ^ b; // 各位相加,不计进位 int carry = (a & b) << 1; // 记下进位 Add_2(sum, carry); // 求sum和carry的和 }}*//**///迭代版本int Add_2(int a, int b){ while (b) { int sum = a ^ b; int carry = (a & b) << 1; a = sum; b = carry; } return a;}
(2)利用数组来计算。
这种办法非常巧妙
思路:
1,数组通过下标的偏移,可以计算出基于首元素地址的某一元素位置,从而访问该元素。
那么我们可以利用编译器的这种行为,来让编译器自动帮我们进行加法运算。
2,32位下, int值与指针的sizeof大小都是4字节。char的大小为1字节。
所以,可以将两数a和b中。a强转为char*类型地址c。这样,b用来表示下标,计算c[b]时,是以1字节为单位计算偏移的。
*/
int Add(int a, int b){ char *c = (char *)a; //将a表示的值,看做是地址c。并且类型要是char*。因为sizeof(char)=1 return (int)&c[b]; //&a[b]-->a+sizeof(char)*b表示地址。通过(int)强转为int值}
由于这种方法是从别处了解,本人第一次见,所以需要仔细分析分析
1,只是用于32平台?
是的,因为通过int值与指针值在32位平台下,都是4个字节,大小一样。所以在解析时,可以通过(char *) 、(int)来相互强转,而不会,多读取或者少读取字节数据。
2,b为负数时,可满足情况?
可以满足。因为,通过数组下标来访问元素的本质,就是基于某个地址的偏移。可以有正偏移(往后偏移),也可以有负偏移(往前偏移)。
测试用例:
int a[5] = {1,2,3,4,5}; int* p = NULL; p = &a[3]; printf("a[-1] = %d\n", p[-1]);//可以查看p[-1]的值是否为3
3,a为负数时,可满足情况吗?
可以满足。因为,在将a值转化为地址c时,会将a的补码序列,看做无符号数。我担心的是,在将有符号数化作无符号数,计算时,会不会出问题。
后来,终于想到,在两个数计算时,其实是他们的补码序列在计算。这样就脱离了正负的约束,只是在读取时,会根据是否有符号来决定是否判断补码的标识位。
所以,不管a的正负,甚至是b的正负,在计算a(有符号)+b(有符号)与计算c(无符号)+b(无符号)结果的二进制补码序列相同。但是(int)会把无符号数强转为有符号的。这样在读取c+b结果表示的二进制补码序列时,是以有符号数的规则来读取的,这与读取a+b的结果相同。
- 17_7_14:逆置单链表+查找单链表的倒数第K个节点+非常规方法实现Add函数
- 逆置,查找倒数第K个节点,Add函数不用四则运算的实现
- day02逆置/反转单链表+查找单链表的倒数第k个节点+实现一个Add函数不用四则运算
- 每日一刷——逆置单链表&&查找倒数第k个节点&&Add函数
- 单链表查找倒数第k个节点
- 单链表查找倒数第k个节点
- 单链表查找倒数第k个节点
- 查找单链表的倒数第k个节点
- 查找单链表倒数第K个节点和以及逆置单链表
- 单链表的倒数第K个节点
- 查找链表中倒数第K个节点
- 查找链表中倒数第k个节点
- 单链表中查找倒数第K个节点
- 查找单链表中倒数第k个节点
- 查找单链表中倒数第k个节点
- 在一个链表中,查找倒数的第k个节点
- C实现简单单向链表,一次遍历查找倒数第k个节点的值
- C语言:【单链表】查找单链表的倒数第k个节点,要求只能遍历一次
- ROS机器人Diego 1#整合Tensorflow MNIST,玩数字识别
- android 延迟执行, TextUtils类
- mac安装Redis可视化工具-Redis Desktop Manager
- Linux环境编译动态库和静态库总结
- 走进weex
- 17_7_14:逆置单链表+查找单链表的倒数第K个节点+非常规方法实现Add函数
- 移动热修复Sophix之初体验
- OBIEE权限控制
- pc和移动端默认样式重置
- Linux下./configure,make,make install的作用
- java中文乱码解决方案
- Java.1面向对象基础
- iOS系统3DTouch全解析
- java反射机制及应用分析