经历经典的数据结构并停止在链表上。只是实现了一个循环的单链表,但是我的压力很大,这个列表可以用更优雅的方式表达,特别是remove_node函数。 记住效率和代码可读性,任何人都可以为单链循环列表提供更简洁有效的解决方案吗?
#include <stdio.h>
#include <stdlib.h>
struct node{
struct node* next;
int value;
};
struct list{
struct node* head;
};
struct node* init_node(int value){
struct node* pnode;
if (!(pnode = (struct node*)malloc(sizeof(struct node)))){
return NULL;
}
else{
pnode->value = value;
}
return pnode;
}
struct list* init_list(){
struct list* plist;
if (!(plist = (struct list*)malloc(sizeof(struct list)))){
return NULL;
}
plist->head = NULL;
return plist;
}
void remove_node(struct list*a plist, int value){
struct node* current, *temp;
current = plist->head;
if (!(current)) return;
if ( current->value == value ){
if (current==current->next){
plist->head = NULL;
free(current);
}
else {
temp = current;
do {
current = current->next;
} while (current->next != plist->head);
current->next = plist->head->next;
plist->head = current->next;
free(temp);
}
}
else {
do {
if (current->next->value == value){
temp = current->next;
current->next = current->next->next;
free(temp);
}
current = current->next;
} while (current != plist->head);
}
}
void print_node(struct node* pnode){
printf("%d %p %p\n", pnode->value, pnode, pnode->next);
}
void print_list(struct list* plist){
struct node * current = plist->head;
if (!(current)) return;
if (current == plist->head->next){
print_node(current);
}
else{
do {
print_node(current);
current = current->next;
} while (current != plist->head);
}
}
void add_node(struct node* pnode,struct list* plist){
struct node* current;
struct node* temp;
if (plist->head == NULL){
plist->head = pnode;
plist->head->next = pnode;
}
else {
current = plist->head;
if (current == plist->head->next){
plist->head->next = pnode;
pnode->next = plist->head;
}
else {
while(current->next!=plist->head)
current = current->next;
current->next = pnode;
pnode->next = plist->head;
}
}
}
答案 0 :(得分:5)
查看Linux内核源代码中的循环链表:http://lxr.linux.no/linux+v2.6.36/include/linux/list.h
它的美丽源于这样一个事实:你没有一个特殊的结构来让你的数据适合列表,你只需要在你希望作为列表的结构中包含struct list_head *
。用于访问列表中项目的宏将处理偏移量计算,以从struct list_head
指针获取数据。
可以在kernelnewbies.org/FAQ/LinkedLists上找到对内核中使用的链表的更详细解释(对不起,我没有足够的业力来发布两个超链接)。
编辑:嗯,这个列表是一个双链表,而不是像你一样的单链表,但你可以采用这个概念并创建你自己的单链表。
答案 1 :(得分:2)
当您将列表头部视为列表元素(所谓的“哨兵”)时,列表处理(特别是循环列表)变得更容易。很多特殊情况都消失了。您可以为sentinel使用虚拟节点,但如果下一个指针在结构中是第一个,则您甚至不需要这样做。另一个重要的技巧是在修改列表时保持指向前一个节点的下一个指针(以便稍后可以修改它)。总而言之,你得到了这个:
struct node* get_sentinel(struct list* plist)
{
// use &plist->head itself as sentinel!
// (works because struct node starts with the next pointer)
return (struct node*) &plist->head;
}
struct list* init_list(){
struct list* plist;
if (!(plist = (struct list*)malloc(sizeof(struct list)))){
return NULL;
}
plist->head = get_sentinel(plist);
return plist;
}
void add_node_at_front(struct node* pnode,struct list* plist){
pnode->next = plist->head;
plist->head = pnode;
}
void add_node_at_back(struct node* pnode,struct list* plist){
struct node *current, *sentinel = get_sentinel(plist);
// search for last element
current = plist->head;
while (current->next != sentinel)
current = current->next;
// insert node
pnode->next = sentinel;
current->next = pnode;
}
void remove_node(struct list* plist, int value){
struct node **prevnext, *sentinel = get_sentinel(plist);
prevnext = &plist->head; // ptr to next pointer of previous node
while (*prevnext != sentinel) {
struct node *current = *prevnext;
if (current->value == value) {
*prevnext = current->next; // remove current from list
free(current); // and free it
break; // we're done!
}
prevnext = ¤t->next;
}
}
void print_list(struct list* plist){
struct node *current, *sentinel = get_sentinel(plist);
for (current = plist->head; current != sentinel; current = current->next)
print_node(current);
}
答案 2 :(得分:1)
一些评论:
答案 3 :(得分:0)
我使用以下内容创建动态循环单链表。所需要的只是尺寸。
Node* createCircularLList(int size)
{
Node *it; // to iterate through the LList
Node *head;
// Create the head /1st Node of the list
head = it = (Node*)malloc(sizeof(Node));
head->id = 1;
// Create the remaining Nodes (from 2 to size)
int i;
for (i = 2; i <= size; ++i) {
it->next = (Node*)malloc(sizeof(Node)); // create next Node
it = it->next; // point to it
it->id = i; // assign its value / id
if (i == 2)
head->next = it; // head Node points to the 2nd Node
}
// close the llist by having the last Node point to the head Node
it->next = head;
return head; // return pointer to start of the list
}
我定义Node
ADT如下:
typedef struct Node {
int id;
struct Node *next;
} Node;