题目:

假设有一个没有头指针的单链表。一个指针指向此单链表中间的一个节点(非第一个节点, 也非最后一个节点)。请将该节点从单链表中删除。

解答:

典型的“狸猫换太子”, 若要删除该节点,正常情况下,应该要知道该节点的前面节点的指针,但是由于单链表中没有头结点,所以无法追溯到该节点前面的那个节点,因此,这里采用了“移花接木”的方法。设该节点为B,下一个节点为C。那么,首先将B节点的内容替换为C节点的内容,然后,将C节点删除,这样就达到了我们的目的。代码如下:

pcur->next = pnext->next;

pcur->data = pnext->date;

delete pnext;

代码:

void DeleteListNode(node* pCurrent)

{

assert(pCurrent != NULL);

node* pNext = pCurrent -> next;

if (pNext == NULL)

pCurrent = NULL;

else

{

pCurrent -> next = pNext -> next;

pCurrent -> data = pNext -> data;

delete pNext;

}

}

类似问题:

1、从无头单链表中删除节点问题:假设有一个没有头指针的单链表,一个指针p指向单链表中的一个节点(不是第一个,也不是最后一个),请将该节点删除掉。

2、向无头单链表中添加节点问题:假设有一个没有头指针的单链表,一个指针p指向单链表中的一个节点(不是第一个,也不是最后一个),请在该节点之前插入一个新的节点q。

由于链表是无头单向链表,所以我们无法由当前节点获得p的前一节点,而无论是删除当前节点还是向前面节点插入新节点都需要获得p的前一节点。在这里我们不妨换一下思路,对当前节点的后继结点进行操作,然后将前后节点的数据进行适当交换也可以得到相应效果。

问题1解法:将p后继结点p->next的数据拷贝到p,然后删除p->next,这样就达到了相同的效果,代码如下:

ListNode* p_next = p->next;

p->value=p_next->value;

p->next=p_next->next;

delete   p_next;

问题2解法:在p节点后添加q,然后交换p和q的数据即可。

q->next=p->next;

p->next=q;

swap(&p->value, &q->value);

假设一个没有头结点的单链表,一个指针指向此单链表中间的一个节点(不是第一个节点也不是最后一个节点),请将该节点从单链表中删除

//删除不带头结点链表中的任意个节点

#include

using namespace std;

typedef struct  node

{

int data;

struct node *next;

}Node;

class List

{

public:

List();

~List();

void CreateList();

void DisplayList();

void DeleteNode(Node *d);

Node* GetNode(int n);

private:

Node * list;

};

List::List()

{

list=NULL;

};

List::~List()

{

if(list)

{

Node *p=list;

while(p)

{

list=p->next;

delete p ;

p=list;

}

}

}

void List::CreateList()   //创建不带头结点的链表

{

int num;

Node *p;

cout<

while(cin>>num)

{

if(!list)  //第一个节点特殊处理

{

list=new Node;

list->data=num;

list->next=NULL;

p=list;

}

else

{

Node *temp=new Node;

temp->data=num;

temp->next=NULL;

p->next=temp;

p=temp;

}

}

}

void List::DisplayList()

{

Node *p=list;

while(p)

{

cout<data<

p=p->next;

}

cout<

}

Node* List::GetNode(int n)  //返回第n个节点

{

Node *p=list;

while(p && --n)

p=p->next;

return p;

}

void List::DeleteNode(Node *d)  //删除节点d

{

Node *pCurrent=d;

Node *pNext=pCurrent->next;  //删除该节点的下一个,然后将data赋给d,进行替换

pCurrent->next=pNext->next;

pCurrent->data=pNext->data;

}

int main()

{

List list;

list.CreateList();

list.DisplayList();

Node *p=list.GetNode(2);

cout<data<

list.DeleteNode(p);

list.DisplayList();

system("pause");

return 0;

}

扩展问题:

将一个单链表,在只遍历一遍的情况下,将单链表中的元素顺序反转过来。

解答:

我的想法是这样的,用三个指针进行遍历,在遍历的途中,进行逆置。

这道题目有两种算法,既然是要反转,那么肯定是要破坏原有的数据结构的:算法:我们需要额外的两个变量来存储当前节点curr的下一个节点next、再下一个节点nextnext:

Java代码

public static Link ReverseLink1(Link head)

{

Link curr = head.Next;

Link next = null;

Link nextnext = null; //if no elements or only one element exists

if (curr == null || curr.Next == null) {

return head;

} //if more than one element

while (curr.Next != null) {

next = curr.Next; //1

nextnext = next.Next; //2

next.Next = head.Next; //3

head.Next = next; //4

curr.Next = nextnext; //5

}

return head;

}

public static Link ReverseLink1(Link head)

{

Link curr = head.Next;

Link next = null;

Link nextnext = null; //if no elements or only one element exists

if (curr == null || curr.Next == null) {

return head;

} //if more than one element

while (curr.Next != null) {

next = curr.Next; //1

nextnext = next.Next; //2

next.Next = head.Next; //3

head.Next = next; //4

curr.Next = nextnext; //5

}

return head;

}

算法的核心是while循环中的5句话 我们发现,curr始终指向第1个元素。此外,出于编程的严谨性,还要考虑2种极特殊的情况:没有元素的单链表,以及只有一个元素的单链表,都是不需要反转的。

C语言实现

非递归方式:这是一般的方法,总之就是用了几个临时变量,然后遍历整个链表,将当前节点的下一节点置为前节点

C代码

void reverse(node*& head)

{

if ( (head == 0) || (head->next == 0) ) return;// 边界检测

node* pNext = 0;

node* pPrev = head;// 保存链表头节点

node* pCur = head->next;// 获取当前节点

while (pCur != 0)

{

pNext = pCur->next;// 将下一个节点保存下来

pCur->next = pPrev;// 将当前节点的下一节点置为前节点

pPrev = pCur;// 将当前节点保存为前一节点

pCur = pNext;// 将当前节点置为下一节点

}

head->next = 0; //将旧head节点设置为尾部节点

head = pPre;  //设置当前遍历的最后一个节点为新的头节点

}

void reverse(node*& head)

{

if ( (head == 0) || (head->next == 0) ) return;// 边界检测

node* pNext = 0;

node* pPrev = head;// 保存链表头节点

node* pCur = head->next;// 获取当前节点

while (pCur != 0)

{

pNext = pCur->next;// 将下一个节点保存下来

pCur->next = pPrev;// 将当前节点的下一节点置为前节点

pPrev = pCur;// 将当前节点保存为前一节点

pCur = pNext;// 将当前节点置为下一节点

}

head->next = 0; //将旧head节点设置为尾部节点

head = pPre;  //设置当前遍历的最后一个节点为新的头节点

}

递归方式:这个方法是采用了递归算法,也就是在反转当前节点之前先反转其后继节点,利用函数的调用堆栈构建了一个临时链表。采用此算法需要注意的是,头结点必须要传入的是引用,因为在递归跳出的时候要切断链表,否则链表将会形成一个回环。

C代码

node* reverse( node* pNode, node*& head)

{

if ( (pNode == 0) || (pNode->next == 0) ) // 递归跳出条件

{

head = pNode; // 将链表切断,否则会形成回环

return pNode;

}

node* temp = reserve(pNode->next, head);// 递归

temp->next = pNode;// 将下一节点置为当前节点,既前置节点

return pNode;// 返回当前节点

}

编写一个函数,给定一个链表的头指针,只要求遍历一次,将单链表中的元素顺序反转过来

#include

using namespace std;

typedef struct node

{

int data;

struct node *next;

}Node;

class List

{

public:

List();

~List();

void CreateList();

void DisplayList() const;

void ReverseList();

private:

Node *head;

};

List::List()

{

//分配头结点

head=new Node;

head->next=NULL;

head->data=0;

}

List::~List()

{

if(head)

{

Node *pCurrent=head;

while(head)

{

pCurrent=head->next;

head=pCurrent;

delete pCurrent;

}

}

}

void List::CreateList()

{

//创建带头结点的链表

int num;

cout<

Node *pCurrent=head;

while(cin>>num)

{

Node *pTemp=new Node;

pTemp->data=num;

pTemp->next=NULL;

pCurrent->next=pTemp;

pCurrent=pTemp;

}

}

void List::DisplayList() const

{

Node *pCurrent=head->next;

while(pCurrent)

{

cout<data<

pCurrent=pCurrent->next;

}

cout<

}

void  List::ReverseList()  //思想是将指针的方向反向。将头节点指向尾节点

{

Node *pCurrent,*pNext,*pTemp;

pCurrent=head->next;  //指向第一个节点

pNext=pCurrent->next;  //第二个节点

if(!pCurrent || !pNext)  //当链表为空或者只含有一个节点

return;

pCurrent->next=NULL;     //将第一个节点变为为节点

while(pNext)

{

pTemp=pNext->next;    //保存下一个节点

pNext->next=pCurrent; //将指针方向

pCurrent=pNext;       //指向当前的节点

pNext=pTemp;          //下一个节点

}

head->next=pCurrent;  //头结点指向最后一个节点

}

int main()

{

List list;

list.CreateList();

list.DisplayList();

cout<

list.ReverseList();

list.DisplayList();

system("pause");

return 0;

}

无头结点单链表的逆置_从无头单链表中删除节点及单链表的逆置相关推荐

  1. 数据结构,单链表讲解,并使用Java代码实现单链表增删改查【尾部添加,中间插入、修改节点、删除节点、展示链表】

    文章目录 单链表 什么是单链表,链式存储结构详解 链表的节点 头节点,头指针和首元节点 单链表的实现 1.尾部添加新节点 思路分析 代码实现 注意事项 2.按照编号插入新节点 思路分析 代码实现 注意 ...

  2. 从无头单链表中删除节点 结构之法 4

    题目: 假设有一个没有头指针的单链表.一个指针指向此单链表中间的一个节点(不是第一个,也不是最后一个节点),请将该节点从单链表中删除. 分析与解答: 假设给定的指针为pCurrent,Node *pN ...

  3. 编程之美-从无头单链表中删除节点方法整理

    [试题描述] 假设有一个没有头指针的单链表.一个指针指向此单链表中间的一个节点(不是第一个,也不是最后一个),请将该节点从单链表中删除. 程序:

  4. 237删除链表中的节点(单链表基本操作)

    1.题目描述 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点. 说明: 链表至少包含两个节点. 链表中所有节点的值都是唯一的. 给定的节点为非末尾节点并且一定 ...

  5. 树状数组求逆序对_算法系列之-数组中的逆序对

    题目来源 剑指offer 01 题目描述 在数组中如果前一个数字大于后一个数字,则称为这个数字组合组成一个逆序对.输入一个数组,求所有的逆序对的总数. 如 数组 {7,5,6,4} 则它的逆序对是 ( ...

  6. 实际应用中带头节点的线性链表

    /*========带头节点的线性链表类型=========*/ typedef char ElemType//结点类型 typedef struct LNode {char data;struct ...

  7. jsp在mysql中删除数据_如何在jsp页面中删除数据库中的数据

    如何在jsp页面中删除数据库中的数据 各位大虾! 我想在jsp页面上写一个按钮功能,从而动态的删除数据库中的一行数据. 不知道怎么实现 这是我写的一段代码 数据库是MySql UserBean p3= ...

  8. svn比较本地与svn差异_如何从SVN差异中删除SVN属性

    svn比较本地与svn差异 I use SVN for my projects version control system. Sometimes I need to see the differen ...

  9. linux终端删除文件命令_如何在Linux终端中删除文件和目录

    linux终端删除文件命令 Fatmawati Achmad Zaenuri/Shutterstock.comFatmawati Achmad Zaenuri / Shutterstock.com T ...

最新文章

  1. 157所中国内地高校上榜!最新世界大学学术排名发布
  2. Delphi 使用双缓冲解决图片切换时的闪烁问题 good
  3. Istio:一个用于微服务间通信的服务网格开源项目
  4. 【Android游戏开发十四】深入Animation,在SurfaceView中照样使用Android—Tween Animation!...
  5. 【杂谈】有三AI知识星球最近都GAN了哪些内容?
  6. C#下实现动态系统托盘图标
  7. CRM订单上状态字段在UI的显示逻辑
  8. MacOS 的 Automator 实用案例详解
  9. Java web后端2 Servlet Maven HttpServlet ServletConfig ServletContext HTTP协议
  10. golang 工作池demo
  11. JVM虚拟机-Class文件之方法表集合
  12. 三维绘图之Mayavi.mlab
  13. 深入了解clientXY,offsetXY,pageXY的区别
  14. Docker安装详细安装步骤
  15. 法语学习(1)--入门资料推荐
  16. 解构SPA模式 ZARA、UNIQLO秘诀
  17. 基于C++和QT实现的个人通讯录管理系统
  18. 高斯消元法小总结和瞎总结
  19. Navicat fro oracle 简体中文破解版(亲测可用)
  20. 计算机专业大学生该买什么配置的电脑,大学生适合买什么配置的电脑?

热门文章

  1. android usb rndis驱动,基于安卓的rndis驱动的usb网络共享的实现
  2. 什么是频谱分析仪?主要功能和应用领域有哪些?主要品牌TFN FMT650的详情介绍
  3. php空格符代码,php如何实现替换空格(代码)
  4. linux离线下载并安装amd64包
  5. 想要安装pdf虚拟打印机64位应如何实现
  6. 23种设计模式之桥接模式
  7. 第5章第15节:案例:创作一份大气、华丽的卷轴动画 [PowerPoint精美幻灯片实战教程]
  8. 20190509 大数据小牛学堂培训全套视频课程资源
  9. H5 连接蓝牙打印机,打印条码、二维码
  10. v-chart 图表曲线图(双曲线)