原题:

双向链表中,需要三个基本数据,一个携带具体数据,一个携带指向上一环节的prev指针,一个携带指向下一环节的next指针。请改写双向链表,仅用一个指针np实现双向链表的功能。定义np为next XOR prev,请根据表头提供的信息,为双向链表编写插入函数、删除函数和查找函数,并在O(1)时间内实现链表的翻转。

分析:

问题的关键,在于怎样利用prev指针和next指针的异或结果,来获得上一节点或下一节点的地址值。也就是说,如何利用异或来算出具体的prev及next值。我们注意到两点:

1、A XOR B = C  =>  C XOR B = A AND C XOR A = B。A、B两个元素的异或结果C,同A异或后得B,同B异或后得A。也就是说,如果我们能获取到next或者prev其中的一个值,我们就能根据np计算出另一个值。

2、双向链表中,头结点的prev值为0,尾结点的next值为0,因此,可以根据这一点,计算出全部的结点prev及next地址。依据第一点,表头信息需要提供头结点的地址。

实现:

C语言中,指针变量中存储的数值不能直接参与异或运算,需要转换为int型变量参与运算,再转换为指针来指定特定的地址。

根据前述分析,定义两个结构体如下:

typedef struct Node

{

int num;

int np;

}Node;

作为结点的结构体,包含结点必须的两个数据:类型为int的num数据单元,和类型为int的np指针,其中np指针中包含了next和prev两个结点的地址。

typedef struct double_train

{

Node *head;

int length;

}double_train;

作为双向链表的表头,提供了链表的大小、头结点两个数据,以供他人操作该链表。

插入函数void Insert(double_train *L , int value):

该函数接受两个参数——链表L和数据value,该函数的功能为将数据value插入表头。具体代码如下:

void

Insert(double_train *L , int value)

{

Node *p = (Node *)malloc(sizeof(Node));

int  temp2;

int  temp1;

p->num = value;

temp2 = (int) L->head;

temp2 = 0 ^ temp2;

p->np = temp2;

//插入一个新节点P,设置prev为0,next为L->head,并表示为np。

if(L->head != NULL)

{

temp1 = (int) p;

temp2 = L->head->np;

L->head->np = temp1 ^ temp2;

}

//若链表非空,则更新原先头结点的np值。

L->head = p;

L->length ++;

}

展示函数 void View(double_train *L):

该函数接受一个参数——链表L,该函数的功能为列出链表L中的所有数据单元。具体代码如下:

void

View(double_train *L)

{

int temp1,Last = 0;

Node *Next;

Node *top = L->head;

int count = L->length;

while(count != 0)        //从头结点开始,根据每个节点的np值遍历链表

{

temp1 = L->head->np ^ Last;

Next = (Node *) temp1;

Last = (int) L->head;

L->head = Next;

count --;

}

L->head = top;

}

删除函数和查找函数代码从略。下面是主函数测试代码,在windows gcc下编译通过并输出正确结果:

int

main(void)             //programmed by wmydx

{

double_train test;

double_train *L = &test;

L->length = 0;

L->head = NULL;  //C并非面向对象,因此不能用构造函数初始化

for(int i = 0;i < 5;i++)

{

Insert(L,i);

}

View(L);

system("pause");

}

那么如何实现在O(1)的时间内对链表进行翻转呢?只需要在链表结构体中加一个记录尾结点 Node *tail的代码,然后exchange tail->np with head->np即可完成。

【原创】《算法导论》链表一章带星习题试解——附C语言实现的更多相关文章

  1. 《算法导论》第二章demo代码实现(Java版)

    <算法导论>第二章demo代码实现(Java版) 前言 表示晚上心里有些不宁静,所以就写一篇博客,来缓缓.囧 拜读<算法导论>这样的神作,当然要做一些练习啦.除了练习题与思考题 ...

  2. 算法导论 第六章 堆排序(python)

    6.1堆 卫星数据:一个带排序的的数通常是有一个称为记录的数据集组成的,每一个记录有一个关键字key,记录的其他数据称为卫星数据. 原地排序:在排序输入数组时,只有常数个元素被存放到数组以外的空间中去 ...

  3. 算法导论 第十三章 红黑树(python)-1插入

    红黑树是上一章二叉搜索树的改进,实现一种平衡 ,保证不会出现二叉树变链表的情况,基本动态集合操作的时间复杂度为O(lgn) 实际用途:c++stl中的set,map是用他实现的 红黑树的性质: 1.每 ...

  4. 算法导论 第三章 and 第四章

    第三章 渐进的基本O().... 常用函数 % 和  // 转换 斯特林近似公式 斐波那契数 第四章 分治策略:分解(递归)--解决(递归触底)--合并 求解递归式的3种方法: 1:代入法(替代法): ...

  5. 算法导论 第六章 思考题6-3 Young氏矩阵

    这题利用二叉堆维持堆性质的办法来维持Young氏矩阵的性质,题目提示中写得很清楚,不过确实容易转不过弯来. a,b两问很简单.直接看c小问: 按照Young氏矩阵的性质,最小值肯定在左上角取得,问题在 ...

  6. 算法导论 第六章 思考题 6-3 d叉堆

    d叉堆的实现相对于二叉堆变化不大,首先看它如何用数组表示. 考虑一个索引从1开始的数组,一个结点i最多可以有d个子结点,编号从id - (d - 2) 到 id + 1. 从而可以知道一个结点i的父结 ...

  7. 算法导论(第三版)习题Exercises4.3(第四章三节)算法导论的一个印刷错误

    本节系列证明都可见4.5节需要说明的有4.3-8,4.3-9两题 4.3-8(本题有误) T(n)=4T(n/2)+n2根据4.5理论,结果为Θ(n2lgn) 4.3-9 m = lgn T(2m) ...

  8. 算法导论 第七章 快速排序(python)

    用的最多的排序 平均性能:O(nlogn){随机化nlogn} 原地址排序 稳定性:不稳定 思想:分治 (切分左右) 学习方式:自己在纸上走一遍   def PARTITION(A,p,r): x = ...

  9. 算法导论 第六章 2 优先队列(python)

    优先队列:     物理结构: 顺序表(典型的是数组){python用到list}     逻辑结构:似完全二叉树 使用的特点是:动态的排序..排序的元素会增加,减少#和快速排序对比 快速一次排完 增 ...

随机推荐

  1. 《转》 Openstack Grizzly 指定 compute node 创建 instance

    声明:此文档仅仅做学习交流使用,请勿用作其它商业用途 作者:朝阳_tony 邮箱:linzhaolover@gmail.com 2013年6月4日9:37:44 星期二 转载请注明出处:http:// ...

  2. FreeSwitch安装和配置记录

    安装FreeSwitch 主要示例,下面的命令: git clone -b v1.2.stable git://git.freeswitch.org/freeswitch.git cd freeswi ...

  3. 如何解决KEIL 5 编KEIL4同RTX系统的project解决方法

    1.我个人KEIL5与KEIL4对照 相较于KEIL 5 的"华丽".笔者还是喜欢KEIL4的"内敛",主要也还是习惯了.懒得换了.由于工作的  原      ...

  4. memwatch的使用

    博主的新Blog地址:http://www.brantchen.com 欢迎訪问:) linux下的測试工具真是少之又少,还不好用,近期试用了memwatch,感觉网上的介绍不太好,所以放在这里跟大家 ...

  5. Wix打包系列(四) 自定义UI

    原文:Wix打包系列(四) 自定义UI 除了标准的安装界面,如果我们要在安装时需要提供一些额外的信息时,这时就需要自定义界面来显示和录入这些信息. 4.1  自定义对话框 如上一章中我们测试数据库的连 ...

  6. hdu1828(线段树——矩形周长并)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1828 分析:与面积不同的地方是还要记录竖的边有几个(num记录),并且当边界重合的时候需要合并(用lb ...

  7. Linux档案种类与扩展名(2013.09.03)

    档案种类: 正规档案(regular file ):    第一个字符为 [ -],例如 [-rwxrwxrwx ].另外,依照档案的内容,又大略可以分为:     纯文本档(ASCII)     二 ...

  8. 阿尔贝我给我加i觉

    http://www.huihui.cn/share/8192186       http://www.huihui.cn/share/8192178       http://www.huihui. ...

  9. Java中的statickeyword具体解释

    1.statickeyword主要有2个作用: ①为某特定的数据类型或者对象分配单一的存储空间.而与创建对象的个数无关. ②在不创建对象的情况下能够直接通过类名来直接调用方法或者使用类的属性. 2.s ...

  10. WPF界面设计技巧(11)-认知流文档 & 小议WPF的野心

    原文:WPF界面设计技巧(11)-认知流文档 & 小议WPF的野心 流文档是WPF中的一种独特的文档承载格式,它的书写和呈现方式都很像HTML,它也几乎具备了HTML的绝大多数优势,并提供了更 ...