再写单链表(不带头单链表)

单链表

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:

  1. 单向、双向
  2. 带头、不带头
  3. 循环、非循环

虽然有这么多的链表的结构,但是我们实际中最常用还是两种结构:
在这里插入图片描述

  1. 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结 构,如哈希桶、图的邻接表等等。另外这种结构在学校的考试中出现很多。
  2. 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向 循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而 简单了

实现不带头单链表以及相关操作

头文件

#pragma oncetypedef int SLDateType;//一个结点
typedef struct SLNode{SLDateType value;struct SLNode *next;
}	SListNode;//不带头动态链表
typedef struct SList{SListNode *first;
}SList;//初始化
void SListInit(SList *list);
//销毁
void SListDestroy(SList *list);
//增
//头插
void SListPushFront(SList *list, SLDateType value);
//尾插
void SListPushBack(SList *list, SLDateType value);//删
//头删
void SListPopFront(SList *list);
//尾删
void SListPopBack(SList *list);//打印
void SListPrint(const SList *list);//改
void SListUpdata(SListNode *node, SLDateType value);//查
//去查找链表中遇到的第一个value,如果没找到,返回NULL
SListNode *SListFind(const SList *list, SLDateType value);//打印
void SListPrint(const SList *list);void SListInsertBefore(SList *list, SListNode *pos, SLDateType value);
// 在pos的后面插入
void SListInsertAfter(SListNode *pos,SLDateType value); 
// 删除pos位置的节点 
void SListEraseAfter(SListNode *pos); 
void ListRemove();

功能实现

#include"SList.h"
#include<stdlib.h>
#include<assert.h>
#include<malloc.h>
#include<stdio.h>//初始化
void SListInit(SList *list){assert(list != NULL);list->first = NULL;
}//申请新结点
SListNode* BuyNode(SLDateType value){SListNode *node = (SListNode*)malloc(sizeof(SListNode));assert(node);node->value = value;node->next = NULL;return node;
}
//头插
void SListPushFront(SList *list, SLDateType value){SListNode *node = (SListNode*)malloc(sizeof(SListNode));assert(node);node->value = value;node->next = list->first;list->first = node;
}//头删
void SListPopFront(SList *list){assert(list != NULL);       //链表存在assert(list->first != NULL);  //链表不为空,里面有结点SListNode *old_first = list->first;list->first = list->first->next;free(old_first);
}
//尾插
void SListPushBack(SList *list, SLDateType value){assert(list != NULL);if (list->first == NULL){ //链表中没有结点的情况就跟头插的情况是一样的SListPushFront(list, value);return;}//链表中有结点的情况SListNode *cur;for (cur = list->first; cur->next != NULL; cur = cur->next);//cur就是最后一个结点SListNode *node = BuyNode(value);cur->next = node;
}//尾删
void SListPopBack(SList *list){assert(list != NULL);assert(list->first != NULL);//只有一个结点if (list->first->next == NULL){SListPopFront(list);return;}SListNode *cur = list->first;while (cur->next->next != NULL){cur = cur->next;}free(cur->next);cur->next = NULL; 
}//销毁
void SListDestroy(SList *list){assert(list != NULL);SListNode *cur = list->first;SListNode *next;while (cur!=NULL){next = cur->next;free(cur);cur = cur->next;}list->first = NULL;
}//打印
void SListPrint(const SList *list){for (SListNode *cur = list->first; cur != NULL; cur = cur->next){printf("%d--->", cur->value);}printf("\n");
}//改
void SListUpdata(SListNode *node, SLDateType value){node->value = value;
}//去查找链表中遇到的第一个value,如果没找到,返回NULL
SListNode *SListFind(const SList *list, SLDateType value){for (SListNode *cur = list->first; cur != NULL; cur = cur->next){if (cur->value == value){return cur;}}return NULL;
}//pos 一定是链表中有效结点
//向后面插入
void SListInsertAfter(SListNode *pos, SLDateType value){SListNode *node = BuyNode(value); //申请结点node->next = pos->next;pos->next = node;
}// 删除pos后面位置的节点 
void SListEraseAfter(SListNode *pos){SListNode *next = pos->next;pos->next = next->next;free(next);}//向pos前面插入
void SListInsertBefore(SList *list, SListNode *pos, SLDateType value){SListNode *cur;SListNode *node = BuyNode(value);for (cur = list->first; cur->next != pos; cur = cur->next);node->next = pos;cur->next = node;
}

测试用例

#include"SList.h"
#include<stdlib.h>
#include<assert.h>
#include<stdio.h>void TestList1(){SList list;SListInit(&list);assert(list.first == NULL);/*SListPushFront(&list, 1);SListPushFront(&list, 2);SListPushFront(&list, 3);//3 2 1*/SListPushBack(&list, 11);SListPushBack(&list, 12);SListPushBack(&list, 13);//3 2 1 11 12 13/*SListPopBack(&list);SListPopBack(&list);SListPopBack(&list);*/SListNode *n12 = SListFind(&list, 12);assert(n12 != NULL);SListPrint(&list);SListInsertAfter(n12, 103);SListPrint(&list);SListEraseAfter(n12);SListPrint(&list);SListInsertBefore(&list,n12, 101);SListPrint(&list);printf("大成功\n");
}int main()
{TestList1();system("pause");return 0;
}

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

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

相关文章

再写双向循环链表

#pragma once #include<assert.h> #include<malloc.h> #include<stdio.h> typedef int DLDataType;//定义链表结点结构 typedef struct DListNode{DLDataType value;struct DListNode *prev; //指向前一个结点struct DListNode *next; //指向后一个结点 } DL…

链表题目--1 删除链表中所有等于val的值

注意事项 要删除的结点相邻第一个结点就是要删除的结点 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* removeElements(struct ListNode* head, int val){if(headNULL){return NULL;}struct …

链表题目--2 求链表的中间结点 和 求链表中倒数第k个结点

求链表的中间结点 思路 一个走两步&#xff0c;一个走一步。一个走到尾&#xff0c;另外一个就走到了中间 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* middleNode(struct ListNode* head…

链表题目---3 合并两个有序单链表 和 分割链表

合并两个有序单链表 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){if(l1 NULL){return l2;}else if(l2 NULL){return l1;}struc…

链表题目---4 删除链表中重复的结点 和 判断链表是否为回文链表

删除链表中重复的结点 /* struct ListNode {int val;struct ListNode *next;ListNode(int x) :val(x), next(NULL) {} }; */ class Solution { public:ListNode* deleteDuplication(ListNode* pHead){if(pHead NULL){return NULL;}ListNode *prev NULL; //用于删除的结点, 是…

链表题目----5 相交链表 和 环形链表 和 返回链表开始入环的第一个节点

相交链表 思路 链表交叉不可能是x型因为有可能两个链表不等长&#xff0c;所以我们必须让他们从同一起跑位置去起跑从同一起跑位置出发&#xff0c;依次比较每个结点的地址是否相同 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct L…

链表题目---6 复制带随机指针的链表

思路 将新结点放在老结点的后面 复制random 将链表拆开 /* // Definition for a Node. class Node { public:int val;Node* next;Node* random;Node() {}Node(int _val, Node* _next, Node* _random) {val _val;next _next;random _random;} }; */ class Solution { publi…

括号匹配问题(c和c++版本实现)

括号匹配问题 思路 遇见左括号入栈&#xff0c;遇见一个右括号弹出栈顶元素右括号入栈前如果栈已经为空&#xff0c;则不匹配如果不为空则读取并弹出&#xff0c;弹出来的元素与右括号做比较&#xff0c;必须匹配&#xff0c;不匹配返回false;如果最后栈里还有元素&#xff0c…

用队列实现栈 AND 用栈实现队列

用队列实现栈 思路 入队列就是入栈出队列的时候&#xff0c;就是把前面size-1个队列中的元素先出&#xff0c;这样最后一个元素就成队首元素了&#xff0c;再把出去的元素再次入队列读栈顶元素&#xff0c;过程和第二步是一样的&#xff0c;就是弹出后&#xff0c;再把它入队列…

最小栈的实现(设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。)

最小栈的实现 思路 两个栈&#xff0c;左边栈接受元素&#xff0c;右边栈存最小的元素入栈时&#xff0c;先入左边栈&#xff0c;随后进行比较&#xff0c;左边和右边栈顶元素进行比较&#xff0c;如果新元素小&#xff0c;就把新元素放在右边的栈顶位置&#xff0c;如果新元素…

再写循环队列----c++实现

再写循环队列 class MyCircularQueue { public:/** Initialize your data structure here. Set the size of the queue to be k. */MyCircularQueue(int k) {array (int *)malloc(sizeof(int)*k);capacity k;size 0;front 0;rear 0;}/** Insert an element into the circu…

再谈二叉树(二叉树概念,二叉树的性质,二叉树的存储结构)

树的概念 树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因 为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。它具有以下的特点&#xff1a;每个…

二叉树题目----1 前序中序后序遍历二叉树并返回相应的遍历(不是打印)

前序遍历 /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*//*** Note: The returned array must be malloced, assume caller calls free().*/ int *array; int size;void _preorde…

二叉树题目----2 检查两颗树是否相同 和 对称二叉树的判定

检查两颗树是否相同 思路 根要相等 p->val q->val左子树相等 isSameTree(p->left,q->left)右子树也要相等 isSameTree(p->right,q->right) /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* …

二叉树题目---3 另一个树的子树 AND 二叉树最大深度

另一个树的子树 思路 两个数都遍历一遍&#xff0c;找到一个根结点相同时&#xff0c;判断以这个根结点为首的二叉树是否相等 前序遍历判断两棵树是否相同对于返回值的处理是难点 bool isSameTree(struct TreeNode *p, struct TreeNode *q) {if(p NULL && q NULL)…

二叉树题目----4 前序遍历重构二叉树 AND 求二叉树中所有结点的个数

前序遍历重构二叉树 思路 整个二叉树用数组存储因为先序遍历它先遍历根&#xff0c;再遍历左&#xff0c;左边没有跑完是不会去遍历右边的&#xff0c;所以遍历左子树&#xff0c;就是数组元素每回向后一个&#xff0c;个数-1遍历右边时&#xff0c;就是数组起始位置左子树跑到…

二叉树的进阶操作---(求二叉树中所有结点个数,求叶子结点个数,求第k层结点个数;在二叉树中查找某一结点;层序遍历;判断是否为完全二叉树)

typedef struct TreeNode {struct TreeNode *left;struct TreeNode *right;char val; }TreeNode;typedef struct Result{TreeNode * root; //构建的树的根结点int used; //构建过程中用掉的val个数 } Result;求二叉树中所有结点个数 void TreeSize(TreeNode *root, int …

c++中的智能指针详解(RAII, auto_ptr的原理及其改进,unique_ptr的原理,shared_ptr的原理,shared_ptr的缺陷及其改进)

为什么需要智能指针 代码中途退出&#xff0c;也能保证资源的合理释放&#xff0c;在c中没有垃圾回收机制的情况下&#xff0c;智能指针就可以保证我们申请的资源&#xff0c;最后忘记释放的问题&#xff0c;防止内存泄露&#xff0c;也帮我们减少了一定的负担&#xff0c;不用…

二叉树题目----5 平衡二叉树 AND 根据二叉树创建字符串

平衡二叉树 /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/int MAX(int a,int b) {return a > b ? a : b; }//求高度 int getHeight(struct TreeNode *root){if(root NULL){…

再写堆(堆的性质,向下调整,建堆,堆的插入删除初始化,堆排序,TopK问题)

堆的概念 如果有一个关键码的集合K{k0,k1,k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储再一个一维数组中&#xff0c;并满足:Ki<K2i1且Ki<K2i1(Ki > K2i1 且 Ki > K2i2),i0,1,2,3…。则称为小堆(或大堆)。将根结点最大的堆叫做最大堆或大根堆&#…