带头结点和不带头结点的尾插法建立双链表

 

带头结点和不带头结点的尾插法建立双链表

一.带头结点的

先介绍存储数据类型为字符型的

//编程建立双链表(data为字符型数据)13-2-1ex3.cpp

//带头结点的双链表

#include<stdio.h>

#include<stdlib.h>

//#include<string.h>

//#include<conio.h>

//#define E_DEBUG

#ifdef E_DEBUG

#define    PRINT      printf

#else

#define    PRINT(...)                  do{}while(0)    

#endif

 

typedef char datatype;

typedef struct student

{

         datatype data;

         struct student *next;

         struct student *pre;

}DNode;

 

DNode *create()

{

         DNode *head, *p, *s;

         datatype x, cycle=1;

         head=(DNode *)malloc(sizeof(DNode));

         p=head; //如果换成带头节点的链表。这里也不能变,切记,不能变成p=head->next;那就错了

         printf("\nplease input the data:\n");

         while(cycle)

     
<think>我们参考引用中的信息来解答关于带头节点的单向循环链表的问题。根据引用[1]:链表分为单链表(包括带头节点、带头节点、循环单链表)双向链表。引用[2]:头结点是必需的,头指针始终指向链表的第一个结点(有头结点则指向头结点,无则指向第一个数据结点)。引用[3]:循环链表可以从任意结点出发访问全部结点,且访问尾结点的时间复杂度为O(1)。引用[5]提供了Java实现带头结点的单向循环链表的示例代码。我们关注的是带头节点的单向循环链表:-特点:没有头结点,头指针直接指向第一个数据结点,且最后一个结点的指针域指向第一个结点(循环)。实现思路:-节点结构:每个节点包含数据域指向下一个节点的指针。-链表结构:只需要一个头指针(head)尾指针(tail)可选(引用[5]中同时使用了headtail)。但为了操作方便(如在尾部插入),我们可以用尾指针或者只用一个头指针(但遍历到尾需O(n))。-操作:包括初始化、插入(头插、尾插、中间插入)、删除、遍历等。以下以Java语言实现一个带头结点的单向循环链表,并实现基本操作。1.定义节点类:```javaclassNode{intdata;Nodenext;publicNode(intdata){this.data=data;this.next=null;//初始时next为null,但在链表中需要指向下一个节点或头节点形成循环}}```2.定义链表类,包含头指针尾指针(可选,这里为了效率使用尾指针,但注意带头节点):```javapublicclassCircularLinkedList{privateNodehead;//指向第一个节点privateNodetail;//指向最后一个节点publicCircularLinkedList(){head=null;tail=null;}}```3.实现操作:插入节点到头部:步骤:-创建新节点。-如果链表为空,则新节点的next指向自己,headtail都指向该节点。-否则,新节点的next指向head,然后将head更新为新节点,同时让尾节点的next指向新节点(即新的头节点)。插入节点到尾部:-如果链表为空,同头部插入。-否则,将新节点插入到尾节点之后,然后更新尾节点为新节点,并让新节点的next指向头节点。具体代码实现如下(包括头插、尾插、删除头部节点、删除尾部节点、打印等):```java//节点类classNode{intdata;Nodenext;publicNode(intdata){this.data=data;}}//单向循环链表类(带头节点)publicclassCircularLinkedList{privateNodehead;privateNodetail;publicCircularLinkedList(){head=null;tail=null;}//在头部插入节点publicvoidinsertAtHead(intdata){NodenewNode=newNode(data);if(head==null){//空链表head=newNode;tail=newNode;newNode.next=head;//循环指向自己}else{newNode.next=head;head=newNode;tail.next=head;//更新尾节点的next指向新的头节点}}//在尾部插入节点publicvoidinsertAtTail(intdata){NodenewNode=newNode(data);if(head==null){head=newNode;tail=newNode;newNode.next=head;}else{tail.next=newNode;//当前尾节点的next指向新节点tail=newNode;//更新尾节点tail.next=head;//新尾节点的next指向头节点}}//删除头部节点publicvoiddeleteAtHead(){if(head==null){System.out.println("链表为空,无法删除");return;}//如果只有一个节点if(head.next==head){head=null;tail=null;}else{head=head.next;tail.next=head;//更新尾节点的next指向新的头节点}}//删除尾部节点(稍微复杂,需要找到尾节点的前一个节点)publicvoiddeleteAtTail(){if(head==null){System.out.println("链表为空,无法删除");return;}//只有一个节点if(head.next==head){head=null;tail=null;}else{//找到尾节点的前一个节点Nodecurrent=head;while(current.next!=tail){current=current.next;}//此时current指向尾节点的前一个节点current.next=head;//跳过尾节点,指向头节点tail=current;//更新尾节点}}//打印链表publicvoidprintList(){if(head==null){System.out.println("链表为空");return;}Nodecurrent=head;System.out.print("循环链表:");do{System.out.print(current.data+"");current=current.next;}while(current!=head);System.out.println();}}```注意:删除尾部节点时,我们需要遍历链表来找到尾节点的前一个节点,时间复杂度为O(n)。如果希望优化,可以考虑使用双向链表,但这里我们讨论的是单向循环链表。此外,在循环链表中,遍历的终止条件再是当前节点为null,而是当前节点回到头节点(即循环一圈)。上述代码实现了基本操作。我们可以测试一下:```javapublicstaticvoidmain(String[]args){CircularLinkedListlist=newCircularLinkedList();list.insertAtHead(2);list.insertAtHead(1);list.insertAtTail(3);list.insertAtTail(4);list.printList();//输出:循环链表:1234list.deleteAtHead();list.printList();//输出:循环链表:234list.deleteAtTail();list.printList();//输出:循环链表:23}```注意:在实现时,需要特别小心循环指针的维护,尤其是在插入删除时。引用[5]中实现的带头结点的单向循环链表(用于约瑟夫环问题)也提供了参考。以上实现满足了带头节点的单向循环链表的基本操作。**相关问题:**1.如何在单链表中查找特定节点?2.循环链表的主要应用场景?3.如何在循环链表的任意位置插入删除节点?4.循环链表的优点与缺点?</think> ### 带头节点的单向循环链表实现及操作 #### 1. 基本概念 带头节点的单向循环链表具有以下特点: - **无头节点**:头指针直接指向第一个数据节点 - **循环结构**:尾节点指针指向第一个数据节点 - **物理非连续**:数据元素通过指针连接实现逻辑顺序[^1] - **头指针作用**:始终指向链表第一个数据节点[^2] #### 2. 节点结构(Java实现) ```java class Node { int data; // 数据域 Node next; // 指针域 public Node(int data) { this.data = data; this.next = null; // 初始化时next为空 } } ``` #### 3. 链表核心操作 **头插法插入节点**[^4]: ```java void insertHead(Node head, int data) { Node newNode = new Node(data); if (head == null) { // 空链表:新节点自循环 newNode.next = newNode; head = newNode; } else { // 非空链表 newNode.next = head; // 找到尾节点并指向新节点 Node tail = head; while (tail.next != head) tail = tail.next; tail.next = newNode; head = newNode; // 更新头指针 } } ``` **遍历操作**: ```java void traverse(Node head) { if (head == null) return; Node current = head; do { System.out.print(current.data + " "); current = current.next; } while (current != head); // 循环终止条件[^3] } ``` **删除头节点**: ```java void deleteHead(Node head) { if (head == null) return; // 单节点链表 if (head.next == head) { head = null; } // 多节点链表 else { Node tail = head; while (tail.next != head) tail = tail.next; tail.next = head.next; // 尾节点指向新头 head = head.next; // 更新头指针 } } ``` #### 4. 实现优势 1. **空间效率**:省去头节点的存储开销 2. **操作统一**:头节点等同于数据节点[^5] 3. **循环优势**:$O(1)$时间访问尾节点[^3] 4. **内存灵活**:动态分配存储空间[^1] #### 5. 应用场景 - 约瑟夫环问题(Josephus problem)[^5] - 轮询任务调度 - 循环缓冲区实现 - 多人回合制游戏逻辑 **注意事项**: - 空链表判断条件:`head == null` - 循环终止须验证指针是否返回起点[^3] - 删除节点需维护循环结构 #### 示例操作流程 ``` 初始化:head = null 插入A:head → A (A.next=A) 插入B:head → B → A (A.next=B, B.next=A) 删除头:head → A (A.next=A) ``` **
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值