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

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;

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/348332.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阿卡接口_阿卡vs风暴

阿卡接口我最近在Twitter的Storm上工作了一段时间,这让我想知道,它与另一个高性能的并发数据处理框架Akka相比如何 。 什么是Akka和Storm? 让我们从两个系统的简短描述开始。 Storm是一种分布式实时计算系统。 在Storm集群上,您执…

c 语言已知两点求第三点,已知3点座标,求第一点到第二点和第三点构成的直线的距离。...

已知3点座标,求第一点到第二点和第三点构成的直线的距离。以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!已知3点座标,求第一点到第二点和第三点构成的直线的距离。解…

连续交付友好的Maven版本

持续交付管道需要可预测的软件和依赖版本。 Maven软件项目中常见的快照版本与“持续交付”背后的动机背道而驰。 为了将快照版本更新为发行版本,开发人员通常手动或通过诸如maven-release-plugin来编辑pom.xml文件。 但是,Maven还提供了将版本号定义为属…

android u盘检测工具,android USBU盘 接入检测

如果是在注册的静态广播一般必须含有以上的权限,这里必须注意添加如果在代码中注册广播则必须iFilter.addDataScheme("file")这样接受广播判断U盘public class RemovableDiskManagerReceiver extends BroadcastReceiver {public RemovableDiskManagerRece…

android 组合属性动画,Android属性动画组合(sequence串行、together并行)

在android中用原生api实现一系列复杂动画会很麻烦,所以对属性动画进行了一定封装,让使用起来更简单,能够按照人的思维依次编写动画。简单效果:使用方法:添加依赖:dependencies { compile"com.steven:A…

jta atomikos_带有Atomikos示例的Tomcat中的Spring JTA多个资源事务

jta atomikos在本教程中,我们将向您展示如何使用Atomikos Transaction Manager在Tomcat服务器中实现JTA多个资源事务。 Atomicos事务管理器为分布式事务提供支持。 这些是多阶段事务,通常使用多个数据库,必须以协调的方式提交。 分布式事务由…

android 音量键 广播,【Android 7.0 Audio】: 按键调节音量的调用过程

转载自http://blog..net/xiashaohua/article/details/53842337只简单描述调用过程,需对照代码看,不画图了,也不贴代码)1.在key Event处理部分,Phonewindow会捕获到音量按键事件,Phonewindow.onkeydown--MediaSessionLe…

台电+android+电话,通话系统_台电 G17s_平板电脑评测-中关村在线

通话系统将两张联通3G的SIM卡插入台电G17s之后,我们来感受一下它通话系统的使用是否令人满意。和一般的双卡Android手机平板一样,该机也不支持热插拔,需要将机器彻底关闭后插入SIM卡再开机。并且在开机后屏幕会弹出SIM卡信息,并询…

在Payara Server和GlassFish中配置密码

回答Stackoverflow问题可以为我发现我最喜欢的开源工具的正式文档中的空白提供很好的反馈。 我在这里回答的问题之一是如何在docker容器中更改Payara Server主密码 。 显然,在标准服务器安装中,这很简单–只需使用asadmin change-master-password命令&am…

功能Java示例 第2部分–讲故事

这是称为“ Functional Java by Example”的系列文章的第2部分。 我在本系列的每个部分中发展的示例是某种“提要处理程序”,用于处理文档。 在上一部分中,我从一些原始代码开始,并应用了一些重构来描述“什么”而不是“如何”。 为了帮助代…

OpenHub框架–下一个有趣的功能

这是有关OpenHub框架的系列文章中的第三篇,第一篇介绍OpenHub框架 ,第二篇介绍异步消息传递模型 。 该系列的最后一篇文章将更详细地介绍其他一些有趣的功能,并说明为什么OpenHub可以成为您的集成项目的理想选择的原因。 节流 节流是一种功…

tcga癌症亚型获取_将亚型多态性与通用多态性相关联的危险

tcga癌症亚型获取Java 5已将通用多态性引入Java生态系统。 即使我们都知道由于泛型类型擦除及其后果而引起的无数警告,这还是对Java语言的重要补充。 通用多态性(也称为参数多态性 )通常与可能预先存在的亚型多态性正交。 一个简单的例子是co…

在生产中运行Java:SRE的观点

作为站点可靠性工程师 (SRE),我确保我们的生产服务高效,可扩展且可靠。 典型的SRE是生产大师,必须对更广泛的体系结构有很好的了解,并精通许多更精细的细节。 SRE是会说多种语言的程序员,这是很…

android 退出多个activity,Android 中 退出多个activity的经典方法

1.使用list集合方式用list保存activity实例,然后逐一干掉import java.util.linkedlist;import java.util.list;import android.app.activity;import android.app.alertdialog;import android.app.application;import android.content.dialoginterface;import androi…

声明jpa批注处理器_如何使用反射基于JPA批注记录您的数据模型

声明jpa批注处理器因此,当您仅可以注释Java类时,使用JPA,Hibernate或EBeans很酷,但是您不是一直希望可以从代码“生成”数据模型的文档吗? 提取JPA / Hibernate和其他验证注释的信息? 假设您的bean中具有所…

在Grails战争中添加“精简” Groovy Web控制台

假设您已将Grails应用程序部署到服务器上–如何查找应用程序的配置方式? 如果您有来源,则可以查看Config.groovy , BuildConfig.groovy等(在这种情况下,我正在谈论Grails 2应用程序,但是这些想法可以推广到…

ubuntu生成密钥和证书_基于浏览器的密钥生成以及与浏览器的密钥/证书存储的交互...

ubuntu生成密钥和证书想象以下情况: 您需要从访问您的网站的用户那里获取一个密钥(在非对称情况下为用户的公共密钥 ),并希望浏览器记住私有部分,而不会因冗长的导入过程而困扰用户。 老实说,实际上&#…

JPA persistence.xml SQL脚本定义

您可以在将在运行时执行的JPA持久性上下文定义中定义并链接到SQL脚本。 有标准化的属性来定义脚本&#xff0c;以分别说明如何创建模式&#xff0c;批量加载数据和删除模式&#xff1a; <persistence version"2.1" xmlns"http://xmlns.jcp.org/xml/ns/persi…

如何使用JPA和Hibernate映射JSON集合

介绍 开源的hibernate-types项目允许您将Java对象或Jackson JsonNode为JPA实体属性。 最近&#xff0c;感谢我们的杰出贡献者&#xff0c;我们添加了对类型安全集合的支持&#xff0c;该集合也可以作为JSON持久化。 在本文中&#xff0c;您将了解如何实现此目标。 Maven依赖 …

android listview mapview,RelativeLayout和并列ListView/MapView

我尝试使用RelativeLayout并排放置ListView和MapView。然而我的MapView总是高于ListView。RelativeLayout和并列ListView/MapView这里是我的main.xml布局&#xff1a;android:orientation"vertical"android:layout_width"fill_parent"android:layout_heigh…