单链表拿到倒数第N个节点

一.实现思路

        转变一下思路,因为单链表是只能正向遍历的,所以遍历的次数为(链表长度-N),拿到的节点即为倒数第N个节点

二.代码实现

    //拿到节点的个数
    public int getNodeNum(Node head) {
        if (head.next == null) {
            return 0;
        }
        int count = 0;
        Node cur = head.next;
        while (cur != null) {
            count++;
            cur = cur.next;
        }
        return count;
    }

    //拿到倒数第index个节点,换一种思路,其实就是正向遍历到(节点个数-index)
    public Node getLastIndex(Node head, int index) {
        if (head.next == null) {
            return null;
        }
        Node cur = head;
        for (int i = 0; i <= getNodeNum(head) - index; i++) {
            cur = cur.next;
        }
        return cur;
    }

#include <stdio.h> #include <stdlib.h> #include <assert.h> typedef int SLTDataType; //定义单链表节点 typedef struct SListNode { SLTDataType data;//数据域 struct SListNode* next;//指针域 }SLTNode; //打印链表 void SLTPrint(SLTNode* phead); //创建新节点 SLTNode* SLTBuyNode(SLTDataType n); //尾插 void SLTPushBack(SLTNode** pphead, SLTDataType n); //头插 void SLTPushFront(SLTNode** pphead, SLTDataType n); //尾删 void SLTPopBack(SLTNode** pphead); //头删 void SLTPopFront(SLTNode** pphead); //查找 SLTNode* SLTFind(SLTNode* phead, SLTDataType n); //指定位置之前插入 void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType n); //指定位置之后插入 void SLTInsertAfter(SLTNode* pos, SLTDataType n); //删除指定位置节点 void SLTErase(SLTNode** pphead, SLTNode* pos); //销毁链表 void SLTDestroy(SLTNode** pphead); //打印链表 void SLTPrint(SLTNode* phead) { SLTNode* cur = phead;//定义指针指向头节点 while (cur != NULL)//最后一个节点的next为空,cur等于空则说明遍历结束 { printf("%d ", cur->data);//访问数据并打印 cur = cur->next;//对cur解引用拿到一个节点的地址,然后赋值给cur,cur就指向了下一个节点 } printf("\n"); } //创建新节点 SLTNode* SLTBuyNode(SLTDataType n) { SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));//动态开辟一个节点大小的内存 if (newnode == NULL)//内存开辟失败,则直接退出程序 { perror("malloc"); exit(1); } newnode->data = n;//将数据赋值给节点的数据域 newnode->next = NULL;//为了确保链表末尾为空指针,所以创建的所有节点默认next为空 return newnode;//将节点返回 } //尾插 void SLTPushBack(SLTNode** pphead, SLTDataType n) { assert(pphead); SLTNode* newnode = SLTBuyNode(n);//创建新节点 if (*pphead == NULL)//头指针为空说明链表为空 { //链表为空,此时插入第一个元素,需要将头指针指向新节点, //而在函数内修改头指针就要传入头指针的地址,也就是二级指针 *pphead = newnode; } else//链表不为空的情况 { SLTNode* cur = *pphead; while (cur->next != NULL)//从头节点开始,循环遍历找到最后一个节点 { cur = cur->next; } cur->next = newnode;//将新节点的地址赋值给最后一个节点的指针域 } } //头插 void SLTPushFront(SLTNode** pphead, SLTDataType n) { assert(pphead);//确保传入的不是空指针 SLTNode* newnode = SLTBuyNode(n);//创建新节点 newnode->next = *pphead;//使新节点的next指针指向原来的第一个节点 *pphead = newnode;//头指针指向新节点 } //尾删 void SLTPopBack(SLTNode** pphead) { assert(pphead && *pphead);//确保传入的不是空指针并且链表不为空 if ((*pphead)->next = NULL)//链表只有一个节点的情况 { free((*pphead)->next);//释放该节点的空间 *pphead == NULL;//改变了头节点的值,所以也要传二级指针 } else//节点大于1的情况 { SLTNode* prev = *pphead; while (prev->next->next != NULL)//循环遍历,使prev指向倒数第二个节点 { prev = prev->next; } free(prev->next);//释放最后一个节点的空间 prev->next = NULL;//将此时的最后一个节点的next制为空 } } //头删 void SLTPopFront(SLTNode** pphead) { assert(pphead && *pphead); SLTNode* next = (*pphead)->next;//保存第二个节点的地址/空指针(只有一个节点时) free(*pphead);//释放第一个节点的空间 *pphead = next;//让头指针指向刚才保存的节点/空指针,也要传二级指针 } //查找 SLTNode* SLTFind(SLTNode* phead, SLTDataType n) { SLTNode* cur = phead; while (cur != NULL)//遍历链表的所有节点 { if (cur->data == n)//匹配成功,返回该节点的地址 { return cur; } cur = cur->next; } return NULL;//没有找到,返回空指针 } //指定位置之前插入 void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType n) { assert(pphead && pos); SLTNode* newnode = SLTBuyNode(n); if (*pphead == pos)//指定位置是头节点的情况 { //进行头插 newnode->next = *pphead; *pphead = newnode; } else { SLTNode* prev = *pphead; while (prev->next != pos)//遍历找到pos节点的前驱节点 { prev = prev->next; } newnode->next = pos;//新节点的next指针指向pos prev->next = newnode;//前驱节点的next指针指向新节点 } } //指定位置之后插入 void SLTInsertAfter(SLTNode* pos, SLTDataType n) { assert(pos);//确保pos不为空指针 SLTNode* newnode = SLTBuyNode(n); newnode->next = pos->next;//newnode的next指向后继节点 pos->next = newnode;//前驱节点的next指向newnode } //删除指定位置节点 void SLTErase(SLTNode** pphead, SLTNode* pos) { assert(pphead && pos && *pphead);//确保传入的不是空指针并且链表不为空 if (pos == *pphead)//指定位置是头节点情况 { //头删 *pphead = pos->next;//先使头指针指向第二个节点 free(pos);//释放掉pos节点 } else { SLTNode* prev = *pphead; while (prev->next != pos)//循环遍历,找到pos的前驱节点 { prev = prev->next; } prev->next = pos->next;//使前驱节点的next指针指向pos的后继节点 free(pos);//释放掉pos节点 } pos = NULL;//对野指针及时制空 } //销毁链表 void SLTDestroy(SLTNode** pphead) { assert(pphead); SLTNode* cur = *pphead;//从头节点开始遍历 while (cur != NULL) { SLTNode* next = cur->next;//先记录下一个节点 free(cur);//释放当前节点 cur = next;//释放后,cur指向记录的节点 } *pphead = NULL;//将头指针制空 根据上面代码,写一个打印信息的函数
最新发布
07-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值