2014-10-27 09:13:00更新

你仔细研究一下我写的 testAsignPoint 和 testAsignPointAgain 函数就会明白为什么你的二级指针无效了。

还是那句话,你要记住,指针就是一个变量,存的是32位数据,记住这个才能真正的理解指针。

另外 @pezy 说有内存漏洞,实际上我的完整代码是下面的,我大学是acm出身的,只有初期才使用真正的指针,后期acm中都是使用数组代表指针的,这才是真正的升华,同样存的是地址,这时只不过地址是数组的下标罢了。

当然,下面的代码我没有使用数组代替指针,不然就没法用指针来讲了。

最后,我加上我的测试的完整代码:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using namespace std;

#ifdef __int64

typedef __int64 LL;

#else

typedef long long LL;

#endif

struct ListNode {

int val;

ListNode *next;

ListNode(int x) : val(x), next(NULL) {}

ListNode(int x, ListNode *next) : val(x), next(next) {}

ListNode():next(NULL) {}

} str[100];

ListNode *deleteDuplicates(ListNode *head) {

while(head && head->next) {

if(head->val==head->next->val) {

head->next = head->next->next;

} else {

head = head->next;

}

}

return head;

}

ListNode *oldDeleteDuplicates(ListNode *head) {

ListNode **pcur=&head; //取得 head 变量的

if(head==NULL||head->next==NULL) {//特判是不是没有元素或者只有一个元素

return head;

}

/*

这个时候 head 是 one 的地址。

pcur 是 head 的地址。

*pcur 就代表 head 了,即 one

(*pcur)->nex 指向 two,所以不结束循环,且比较相等了

所以你给 *pcur 赋值,也就是给 head 赋值。

此时 *pcur 就指向 two 了。

*/

while((*pcur)->next!=NULL) {

if((*pcur)->val==(*pcur)->next->val) {

*pcur=(*pcur)->next;

// (*pcur)->next =((*pcur)->next->next);

} else {

pcur=&((*pcur)->next);

}

}

return head;

}

void testAsignPoint(ListNode *head) {

printf(" asign begin=%0x\n",head);

head = head->next;

printf(" asign begin=%0x\n",head);

}

void myprintf(ListNode* head) {

while(head != NULL) {

printf("%d ", head->val);

head=head->next;

}

printf("\n");

}

void testAsignPointAgain(unsigned int addr){

printf(" asign begin=%0x\n",addr);

addr = (unsigned int)((ListNode *)addr)->next;//28fef8

printf(" asign begin=%0x\n",addr);

}

void test(ListNode* ptest) {

printf("ptest begin=%0x\n",ptest);//28fef0

testAsignPoint(ptest);

printf("one ptest =%0x\n",ptest);//28fef0

printf("same as before code");

testAsignPointAgain((unsigned int)(ptest));

printf("one ptest =%0x\n",ptest);//28fef0

printf("ptest=%0x\n",ptest);

myprintf(ptest);

oldDeleteDuplicates(ptest);

myprintf(ptest);

deleteDuplicates(ptest);

printf("ptest=%0x\n",ptest);

myprintf(ptest);

}

void testSample(){

ListNode three(1, NULL);

ListNode two(0, &three);

ListNode one(0, &two);

test(&one);

}

int main() {

int n = 10;

for(int i=0; i

str[i].val = i/2;

str[i].next = &str[i+1];

}

str[n].val = n/2;

str[n].next = NULL;

printf("deleteDuplicates begin\n");

myprintf(str);

deleteDuplicates(&str[0]);

myprintf(str);

printf("deleteDuplicates end\n");

printf("\n");

printf("test Asign Point begin\n");

testSample();

printf("test Asign Point begin\n");

return 0;

}

分割线

更新时间:2014-10-26 15:28

先告诉你我对指针的定义:指针可以理解为一个类型,或者一类类型。和int,double,自定义类型等是没有区别的。

实际上最简洁的代码是下面的样子

ListNode *deleteDuplicates(ListNode *head) {

while(head && head->next) {

if(head->val==head->next->val) {

head->next = head->next->next;

} else {

head = head->next;

}

}

return head;

}

之所以你使用错误,根本原因是由于你错误的理解了指针:以指针为参数,只会修改指针的值,如果对指针变量修改,原来那个指针是不受影响的。

前端时间刚好我看了一本书《重构~改善既有代码的设计》,里面的一个重构目标就是对于串的指针全部改成 final, java 中没有指针,但是传的对象全部是引用,如果添加为 final 就是不能给变量赋值,但是可以修改对象里面的值。c 语言的 const 也有这个漏洞,算是hack做法吧,不推荐。

扯远了,回头来看你的问题,不理解的时候最简单的方法就是自己模拟一下。

假设有链表有三个元素

ListNode three(1, NULL);

ListNode two(0, &three);

ListNode one(0, &two);

结构是这个样子:one -> two -> three

为了传入指针,我们事先一个函数吧。

void test(ListNode* pTest){

printf("head=%0x\n",pTest);

deleteDuplicates(pTest);

printf("head=%0x\n",pTest);

}

test(&one);

对于这个 pTest以参数形式传给deleteDuplicates,由于不是引用,所以传进去的是一个32位数据,可以称为地址。

接下来我们模拟一下你的函数:

ListNode *oldDeleteDuplicates(ListNode *head) {

ListNode **pcur=&head; //取得 head 变量的

if(head==NULL||head->next==NULL) {//特判是不是没有元素或者只有一个元素

return head;

}

/*

这个时候 head 和 pTest 的值一样,都是 one 的地址。

pcur 是 head 的地址。

*pcur 就代表 head 了,即 one

(*pcur)->next 指向 two,所以不结束循环,且比较相等了

所以你给 *pcur 赋值,也就是给 head 赋值。

此时 *pcur 就指向 two 了。

而此时 pTest 还是指向 one 的,而one还是指向two的。

模拟至此,下面再看看为什么是这个样子。

*/

while((*pcur)->next!=NULL) {

if((*pcur)->val==(*pcur)->next->val) {

*pcur=(*pcur)->next;

// (*pcur)->next =((*pcur)->next->next);

} else {

pcur=&((*pcur)->next);

}

}

return head;

}

为什么 pTest 没有改变呢?

我们再测试一下。

void testAsignPoint(ListNode *head) {

printf(" asign begin=%0x\n",head);

head = head->next;

printf(" asign begin=%0x\n",head);

}

void test(ListNode* ptest) {

printf("test begin=%0x\n",ptest);

testAsignPoint(ptest);

printf("test end =%0x\n",ptest);

}

test(&one);

输出时下面的数据

test begin=28fef0

asign begin=28fef0

asign begin=28fef8

test end =28fef0

ptest 的地址是不会改变的,因为你传的是 ptest 的值,而不是 ptest 的地址。

分割线

原始回答:

根据你的算法:*pcur=(*pcur)->next;得到一个结论: 当重复时,你删除的是前一个

但是如果头部重复的时候,你只是改变一下指针,这样的算法肯定不能解决头部问题的。

你需要改变算法为:当重复的时候,删除后一个。

即使后面的你一定要使用你的那个算法,那头部就只有特判然后使用 重复时删除后面的 算法

删除后一个的算法如下:

ListNode *deleteDuplicates(ListNode *head) {

ListNode **pcur=&head;

if(head==NULL||head->next==NULL) {

return head;

}

while((*pcur)->next!=NULL) {

if((*pcur)->val==(*pcur)->next->val) {

// *pcur=(*pcur)->next;

(*pcur)->next =((*pcur)->next->next);

} else {

pcur=&((*pcur)->next);

}

}

return head;

}

c语言中删除有序数组中重复元素,去除有序列表中的重复元素相关推荐

  1. php重置下标有什么用,怎么在PHP中删除空数组并重置数组键名

    怎么在PHP中删除空数组并重置数组键名 发布时间:2021-03-19 17:06:33 来源:亿速云 阅读:60 作者:Leah 本篇文章给大家分享的是有关怎么在PHP中删除空数组并重置数组键名,小 ...

  2. Python列表(获取列表中指定元素的索引、获取列表中的多个元素、判断指定元素是否在列表中存在、列表元素的遍历、列表元素的增加操作、 列表元素的删除操作、列表元素的修改操作、列表元素的排序操作)

    1.获取列表中指定元素的索引 eg1:未指定索引范围查找索引 zyr=['憨憨','憨宝'] print(zyr.index('憨宝')) print(zyr[1]) eg2:在指定索引范围内查找元素 ...

  3. python查找列表重复项_python – 在列表中查找项目和重复项

    我正在使用 Python并考虑以下问题:给出一个列表,例如[1,0,-2,0,0,4,5,0,3]多次包含0的整数,我希望有这些0和每一个的索引是它出现在列表中的次数,直到出现不同的元素或列表结束. ...

  4. 合并两个有序数组python_合并两个有序数组.py

    # 合并两个有序数组 # 给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组. # # 说明: # 初始化 nums1 和 ...

  5. scala集合中添加元素_如何在Scala中将元素添加到列表中?

    scala集合中添加元素 In Scala, lists are immutable data structures in which adding new elements is not allow ...

  6. Java 使用LinkedList模拟KTV点歌系统,首先先添加若干歌曲,如果歌曲列表中已有该歌曲,则不加入,否则追加。`然后选择列表中的其中一首置顶,最后选择列表中一首歌曲前置一位。

    使用LinkedList模拟KTV点歌系统 该系统的任务是执行3个操作:首先先添加若干歌曲,如果歌曲列表中已有该歌曲,则不加入,否则追加.`然后选择列表中的其中一首置顶,最后选择列表中一首歌曲前置一位 ...

  7. chatgpt赋能python:如何去除Python列表中的中括号

    如何去除Python列表中的中括号 在Python中,列表是一个非常重要的数据类型.它可以存储多个不同类型的元素,并且可以动态地增加或删除元素.但是,有时候我们需要将列表中的元素取出来,而不想要中括号 ...

  8. android 如何实现无限列表,在Android中解析和创建无限/无限级别的List /子列表中的XML...

    在我的Android Application的服务器端应用程序也由我开发.在这个应用程序Android应用程序从服务器请求一些XML并解析它. XML包含描述应用程序中应该有多少标签的信息,并且每个标 ...

  9. python怎么查询元素是否在列表中_python怎么判断某一元素是否在列表中

    定义一个列表,并判断元素是否在列表中. python学习网,大量的免费python基础教程,欢迎在线学习! 例如:test_list = [ 1, 6, 3, 5, 3, 4 ] print(&quo ...

  10. JAVA中修改顺序表中的元素_java – 在列表中查找元素并使用stream()更改它

    如果您的目标是只找到一个元素,那么您可以这样做 MyItem item = l.stream() .filter(x -> x.getValue() > 10) .findAny() // ...

最新文章

  1. ceph pool 管理(基础操作)
  2. 迷失只是暂时 2011-03-13
  3. 一起玩树莓派3+手把手带您入门树莓派(3000字+超详细图解版)
  4. 去除tab、空格、回车符等使用replace语句
  5. 【2018.3.31】模拟赛之二-ssl2407 负进制【贪心】
  6. leetcode 327. 区间和的个数(treemap)
  7. GFM与博客园markdown测试
  8. JSK-12 最后一个单词的长度【入门】
  9. java servlet ajax_javaweb中ajax请求后台servlet(实例)
  10. 从零开始搭建webpack+react开发环境
  11. [转]iOS技巧之获取本机通讯录中的内容,解析通讯录源代码
  12. Chrome 插件开发
  13. java gui 数独_数独-GUI开发
  14. CRC校验和CRC各种算法
  15. ssm仓库管理系统含论文
  16. 数据结构课程 -- 学期总结
  17. idea实现打包springboot项目并且运行在cmd中
  18. guid主分区表损坏如何处理_GUID分区表简介
  19. AWS IOT C++ SDK 使用
  20. 《TensorFlow深度学习》学习笔记--10.卷积神经网络--1.LeNet-5实战

热门文章

  1. 在Hotspot JVM中跟踪过多的垃圾回收
  2. Apache Commons Lang StringUtils
  3. RESTful Web服务可发现性,第4部分
  4. javascript等待异步线程完成_前端:什么是单线程,同步,异步?彻底弄懂 JavaScript 执行机制...
  5. Shell(bash) 介绍
  6. Linux 命令之 Bang(!) 命令
  7. 深度学习pytorch--线性回归(二)
  8. emacs python ide_Emacs Python IDE win7 x64
  9. okhttp 连接池_okhttp 源码分析
  10. securecrt哪个版本好用_电脑跑分测试软件哪个好?好用的电脑跑分软件推荐