C 链表:使用最后一个指针在末尾插入
我正在学习链表,想知道我为在链表末尾插入元素而编写的以下程序(基本上是insertaden函数)是否正确 基本思想是*HEAD指向列表的第一个元素,*LAST指向最后一个元素。这节省了遍历列表的最后一个元素然后添加元素的时间和计算C 链表:使用最后一个指针在末尾插入,c,linked-list,C,Linked List,我正在学习链表,想知道我为在链表末尾插入元素而编写的以下程序(基本上是insertaden函数)是否正确 基本思想是*HEAD指向列表的第一个元素,*LAST指向最后一个元素。这节省了遍历列表的最后一个元素然后添加元素的时间和计算 #include<stdio.h> #include<stdlib.h> // Structure for the list element/node struct node { int data; // Stores the data
#include<stdio.h>
#include<stdlib.h>
// Structure for the list element/node
struct node
{
int data; // Stores the data
struct node *next; // Points to the next element in the list.
};
int InsertAtEnd(struct node **, struct node **, int); /*Declaration of the function which
inserts elements at the end.*/
int main()
{
struct node *HEAD=NULL; //Points to the first element in the list.
struct node *LAST=NULL; //Points to the last element in the list.
int i=1;
for(i=1;i<11;i++)
{
InsertAtEnd(&HEAD,&LAST,i);
}
}
// Function to insert element at the end.
int InsertAtEnd(struct node **headref,struct node **lastref,int i)
{
struct node *newnode=malloc(sizeof(struct node)); /*Allocates memory for the newnode
and store the address in pointer
newnode*/
newnode->data=i; // Assign value to the data variable of the newnode.
newnode->next=NULL; // Assign NULL to the next pointer of the newnode.
if(*headref==NULL) //Checks if the list is empty.
{
*headref=newnode; // Places the address of the new node in HEAD pointer.
*lastref=newnode; // Places the address of the new node in LAST pointer.
return 0; //Exit function
}
/* If the list is not empty, then make the next pointer of the present last node point to the new node*/
(*lastref)->next=newnode;
*lastref=(*lastref)->next; // Increment LAST to point to the new last node.
return 0;
}
#包括
#包括
//列表元素/节点的结构
结构节点
{
int data;//存储数据
struct node*next;//指向列表中的下一个元素。
};
int insertaden(结构节点**,结构节点**,int)/*功能声明
在末尾插入元素*/
int main()
{
struct node*HEAD=NULL;//指向列表中的第一个元素。
struct node*LAST=NULL;//指向列表中的最后一个元素。
int i=1;
for(i=1;idata=i;//为newnode的数据变量赋值。
newnode->next=NULL;//将NULL分配给newnode的下一个指针。
if(*headref==NULL)//检查列表是否为空。
{
*headref=newnode;//将新节点的地址放在HEAD指针中。
*lastref=newnode;//将新节点的地址放在最后一个指针中。
返回0;//退出函数
}
/*如果列表不为空,则使当前最后一个节点的下一个指针指向新节点*/
(*lastref)->next=newnode;
*lastref=(*lastref)->next;//递增LAST以指向新的最后一个节点。
返回0;
}
我想特别问的问题是:
a) 上述用于在末尾添加元素(即InsertAttend函数)的代码是否正确?(注意:我在我的机器上测试了它,它按预期工作。但我仍然想从你们那里确认)
b) 代码(插入函数)是否有效
c) 如果我尝试制作更长的列表,代码(InsertAtEnd函数)的效率是否会受到影响
d) 是否有更有效、更简单的算法在最后插入元素?你能告诉我它们在哪里吗?这段代码与列表的大小无关(除了空的特殊情况),也就是说,它是一个常数时间算法。所以很难想出一个更有效的插入算法 但是,唯一可以改进的部分是使用
malloc()
。看起来您正在单独分配每个节点。如果您准备使用比您真正需要的更多内存,您可能会考虑同时分配多个节点,因此对<代码> MALROCK()/<代码>的调用更少。因此,当您尝试创建节点时,它首先检查池中是否还有空闲节点。如果是,那么只需连接指针即可。如果没有,您将需要分配一个新池。显然,这需要更复杂的代码。a)这似乎是正确的
b) 是的。您可以使函数return为void,因为您不需要该int返回值
c) 不。换句话说,执行时间是恒定的
d) malloc需要时间。您可以使用缓冲技术,提前malloc一块节点,然后从缓冲区中获取下一个节点。当缓冲区变为empy时,分配另一个块。区块维度可以使用统计算法进行配置,甚至(复杂)计算
此外,您不检查malloc的NULL返回,但它可能会失败 a)不检查malloc的结果。在内存不足的情况下,它可能返回NULL,从而导致崩溃。我相信算法的其余部分是正确的
B+C+D)效率很高;插入最后一个元素所需的时间是恒定的,这是O(1)Menning。事实上,我想不出一个更简单、更有效的算法。a)是的,它应该可以工作(假设您的列表从未损坏,并且具有headref!=NULL但lastref==NULL)
如果返回值始终为0,那么返回值的意义是什么
b) 当然,除了为每个节点分配内存之外。这是您的设计决策,但不同的解决方案将更加复杂,超出本练习的范围
至于函数本身——链表的优点是它们是O(1)。现在删除一个元素是另一回事,除非你有一个双链接列表,否则删除速度会慢一些
c) 不,是O(1)。如您所见,没有循环或任何相关内容,无论列表中有5个或5000个元素,您都会执行完全相同的步骤
d) 通过使用sentinel,即使用虚拟节点代替headref,可以避免检查列表是否为空。您只需在内存中的某个位置放置一个节点,并将lastref设置为该节点。现在,您不需要将空列表作为特例来处理。a)我认为您的代码在某种意义上是正确的,它完成了您期望它完成的任务。您可能需要检查malloc
的返回值
b) 我认为你的代码也很有效。我唯一能想到的是下一行*lastref=(*lastref)->next代码>我将替换为*lastref=newnode代码>。但我认为几乎每个编译器都会自动对其进行优化
c) 您的方法具有常量runtime(O(1)),因此添加到更大的列表不会更改runtime。但是,如果元素连续存储在内存中,遍历列表的速度可能会更快
d) 我不认为insertAtEnd
可以更快地实现。您可以尝试在内存中连续存储元素,并检查是否返回malloc
我个人在实施这些东西时所做的唯一一件事是:
- 为整个链表数据结构创建自己的结构(持有
大小和头-和最后一个元素-指针)
- 我不会将列表限制为包含整数,而是包含任意元素(因此
void*
s)
int InsertAtEnd(struct node ***, int); /*Declaration of the function which
inserts elements at the end.*/
struct node *HEAD=NULL; //Points to the first element in the list.
struct node **LAST=&HEAD; //Points to the last (NULL) *pointer* in the list.
// Function to insert element at the end.
int InsertAtEnd(struct node ***lastrefref,int i) // no need to pass HEAD
{
struct node *newnode=malloc(sizeof(struct node)); /*Allocates memory for the newnode
and store the address in pointer
newnode*/
// And here we should be checking for errors...
newnode->data=i; // Assign value to the data variable of the newnode.
newnode->next=NULL; // Assign NULL to the next pointer of the newnode.
**lastrefref = newnode; // Put new element at end of list
*lastrefref=&(newnode->next); // Update last pointer location
}
struct <anything> ***