今天再次学习了一下数据结构关于链表的操作,嘿嘿。
链表的节点包含三个数值,* next:指针指向下一个的节点,value:链表的值,name[]:链表的名字,改名字指向该节点所分配的地址。
struct A{
struct A * next;//无论是指向int char等任何类型都只占4个字节的空间
int value;//占4个字节的空间
char name[0];//空字符串数组,不占内存空间
}
现在测试一下:
main()
{ struct A text;
printf("the text size is:%d\n",sizeof(text));
system("pause");
}
显示:the text size is:8
上面的所有就是为了说明一个问题:char name[] 是不占内存空间的。那么这样做有什么好处呢,那么就假设他是指针类型的吧。
struct A{
struct A * next;//无论是指向int char等等任何类型都只占占4个字节的空间
int value;//占4个字节的空间
char * name;//占4个字节的空间
}
由上面可以知道,如果是指针类型的,则占用了4个字节的内存空间,再往下看:
1、char name[]的情况:
现在假设要在一条链表里面插入一个新的节点,而且这个节点的value值所占的内存空间为9,加上后面“\n“所占的一个字节,就需要分配10+sizeof(A)个字节的内存空间:
struct A *p = (struct A*)malloc(sizeof(struct A)+10);
那么name[]的第一个元素就会指向分配地址的首地址。
2、char *p的情况:
同样是在一条链表里面插入一个新的节点,需要分配10+sizeof(A)个字节的内存空间:
//声明一个A的节点空间,并且将*p指向该节点。
struct A *p = (struct A*)malloc(sizeof(struct A));
//为节点开辟一个新的空间存储value值,指针name指向该空间的首地址。
struct ->name = (char *)malloc(10*(sizeof(char)));
根据上述几个过程可以得出:
1、用数组(char name[])做为链表的结构体类型,它所占的内存空间比指针(char *name)小。
2、如果是数组(char name[])的话,则只需一次动态分配内存地址空间即可。指针(char *p)则需要两次分配。
3、一般在操作系统里面,我们希望分配的内存是一块连续的区域,第一种方法很好的做到了这一点。第二种方法由于是两次动态分配,很难分配在一个连续的内存空间。而且很大程度上浪费了内存(比如出现内碎片和外碎片的情况)。
分享到:
相关推荐
总之,头插法是链表操作中的一个重要技巧,它在特定场景下能够提供高效和便捷的插入操作。理解和掌握头插法对于理解链表和相关数据结构的设计至关重要。在编写代码时,根据实际需求选择合适的插入方法,能有效优化...
1. **链表节点**:链表由一系列节点构成,每个节点包含两部分:数据域(存储实际信息)和指针域(指向下一个节点的地址)。头节点是链表的第一个节点,通常用于遍历整个链表。 2. **链表的创建**: - **初始化**:...
1. **链表创建**:在C++中,我们首先定义一个结构体或类来表示链表节点,例如: ```cpp struct ListNode { int data; ListNode* next; }; ``` 然后可以通过指针来初始化链表的头节点,通常设置为nullptr,表示空...
2. **结构体**:为了定义链表节点,我们需要创建一个结构体,例如`struct SnakeNode`,其中包含蛇的位置和指向下一个节点的指针。结构体可以用来封装多种类型的数据,使其成为处理复杂数据的有力工具。 3. **内存...
`DoubleLinkNode`可能是定义链表节点的类,它可能包含数据成员(如`data`)、前向指针`next`和后向指针`prev`。此外,可能还有一个`DoubleLinkedList`类,它是链表的主体,实现了上述的各种操作方法。 测试代码通常...
在C++中,我们可以使用结构体或类来定义链表节点。例如,创建一个简单的单链表节点可以这样表示: ```cpp struct ListNode { int data; // 数据域 ListNode* next; // 指针域,指向下一个节点 }; ``` "聪明的...
1. **链表节点结构**:通常,链表节点由数据域(用于存储数据)和指针域(用于存储指向下一个节点的引用)组成。例如,在C++中,可以定义为: ```cpp struct Node { int data; Node* next; }; ``` 2. **链表...
迭代方法通过比较两个链表的节点值,将较小的节点插入到结果链表中。具体步骤如下: 1. **边界条件检查**:如果其中一个链表为空,则直接返回另一个链表。 2. **初始化指针**:定义指针 `p1` 和 `p2` 分别指向两个...
C语言中,我们可以使用结构体来定义链表节点,包含两个部分:存储人的编号的数据域和指向下一个节点的指针。 C语言循环链表的实现涉及以下几个关键点: 1. 结构体定义:创建一个结构体,如`struct Node`,包含一个...
首先,`g_list.h` 文件通常会定义链表的数据结构,可能包括链表节点的结构体和链表操作的函数原型。在C语言中,链表节点通常包含两个部分:数据域(用于存储实际的数据)和指针域(用于链接下一个节点)。例如: ``...
创建链表节点时,需要动态分配内存;在操作链表后,如不再使用,记得释放内存以防止内存泄漏。C++中的智能指针可以自动管理内存,但在处理链表时仍然需要注意引用计数的问题。 总结来说,链表是数据结构的基础,...
它接收链表头节点和待插入的新学生节点,根据学号将新节点插入到正确的位置。如果链表为空,新节点成为头节点;否则,根据学号比较决定是在当前节点之前还是之后插入新节点。 总结来说,这个程序提供了一个基本的...
可以采用双指针技术,比较两个链表的当前节点,将较小的节点添加到结果链表中。 7. **判断链表环**:检查链表中是否存在环。Floyd's Cycle-Finding Algorithm(快慢指针)是常用的方法,快指针每次移动两个节点,慢...
链表的长度可以在运行时动态调整,插入和删除操作相对快速,只需要改变相邻节点的指针即可。但相比于顺序表,链表访问元素的速度较慢,因为需要遍历指针链。 在C++中实现链表,通常会定义一个节点结构体或类,包含...
首先创建新节点,然后遍历链表找到最后一个节点,将新节点插入其后,并更新最后一个节点的`next`指针。 【链表操作的注意事项】 - 链表操作中内存管理很重要,创建节点时要使用`malloc`分配内存,操作结束后记得...
在尾部插入时,遍历到链表末尾,新节点的prev指针指向当前尾节点,尾节点的next指针指向新节点。 3. **删除节点**:需要找到待删除节点,然后更新其前后节点的指针。如果删除的是头结点,需要更新头结点;如果删除...
5. **链表排序**:使用直接插入排序,从第二个节点开始,依次将每个节点插入到已排序的链表中。比较当前节点的值与已排序链表的节点值,如果小于,则找到合适的位置插入,保持非递减顺序。 6. **合并链表**:首先...
在C++中,我们通常定义一个结构体或类来表示链表节点,包含一个数据成员和一个指向下一个节点的指针。增删改查(CRUD)操作在单链表中执行,通常包括插入新节点、删除特定节点、更新节点值以及遍历链表。由于单链表...
重复此过程直到所有节点插入完毕。 3. 逆序排序:逆序排序即按降序排列,可以使用反向遍历的方法,创建一个新的链表,依次将原链表中的节点添加到新链表的头部,这样新链表就是原链表的逆序。另外,也可以在原链表...
插入节点可以在链表的开头(头部插入)或结尾(尾部插入),也可以在特定位置插入。删除节点需要找到待删除节点的前一个节点,然后更新其指针。遍历链表则涉及从头节点开始,沿着指针序列访问每个节点。打印链表通常...