您的位置:首页 > 编程语言 > C语言/C++

链表(Linked List)的C语言实现

2017-08-20 23:40 417 查看
链表中的各对象按线性顺序排列,而其顺序是由各个对象里的指针所决定的。

链表有多种形式,它可以是单链接的或者双链接的,可以是已排序的或未排序的,可以是循环的或非循环的。

定义的结构体以及函数如下:

typedef struct SINGLE_LINKED_LIST
{
Node * head;
Node * tail;
} SLL;
typedef struct CIRCULAR_SINGLE_LINKED_LIST
{
Node * head;
Node * tail;
} CSLL;
typedef struct DOUBLE_LINKED_LIST
{
Node * head;
Node * tail;
} DLL;
typedef struct CIRCULAR_DOUBLE_LINKED_LIST_WITH_SENTINEL
{
Node * nil;
} CDLLS;

void linked_list_traverse(Node * L);
void linked_list_free(Node* L);

Node* single_linked_list_insert(SLL * L, item_t item);
Node* single_linked_list_search(SLL * L, item_t item);
int single_linked_list_delete(SLL * L, Node * node);

Node* circular_single_linked_list_insert(CSLL * L, item_t item);
Node* circular_single_linked_list_search(CSLL * L, item_t item);
int circular_single_linked_list_delete(CSLL * L, Node * node);

Node* double_linked_list_insert(DLL * L, item_t  item);
Node* double_linked_list_search(DLL * L, item_t item);
int double_linked_list_delete(DLL * L, Node * node);

CDLLS* circular_double_linked_list_with_sentinel_init();
Node* circular_double_linked_list_with_sentinel_insert(CDLLS * L, item_t item);
Node* circular_double_linked_list_with_sentinel_search(CDLLS * L, item_t item);
int circular_double_linked_list_with_sentinel_delete(CDLLS * L, Node * node);


几个公共函数如下:

//functions for all kind of linked list
void linked_list_traverse(Node* L) {
if (L == NULL) {
printf("Empty Linked List.\n");
}
Node * pos = L;
while (pos != NULL) {
printf("%2d is in location:%9p. prev is %9p. next is %9p.\n", pos->item.key, \
pos, pos->prev, pos->next);
pos = pos->next;
if (pos == L) return;
}
}

void linked_list_free(Node* L) {
Node * pos = L;
Node * f = L;
while (pos != NULL && pos != L) {
f = pos;
pos = pos->next;
free(f);
}
}
//-----------------------------------------------------------------------


单链接的未排序非循环链表可以如如下实现:

//functions for single linked list
Node* single_linked_list_insert(SLL * L, item_t item) {
Node * node = (Node*)malloc(sizeof(Node));
node->item = item;
node->prev = NULL;
node->next = L->head;
if (L->tail == NULL)
L->tail = node;
L->head = node;
return node;
}
Node* single_linked_list_search(SLL * L, item_t item) {
if (L->head == NULL) {
fprintf(stderr, "The single linked list is empty.\n");
return NULL;
}
Node * pos = L->head;
while (pos != NULL) {
if (item.key == pos->item.key)
return pos;
pos = pos->next;
}
fprintf(stderr, "The item cannot be found.\n");
return NULL;
}
int single_linked_list_delete(SLL * L, Node * node) {
if (L->head == NULL) {
fprintf(stderr, "The single linked list is empty.\n");
return 0;
}
if (node == NULL) {
fprintf(stderr, "The node is NULL.\n");
return 0;
}
if (L->head == node) {
L->head = node->next;
if (L->head == NULL)
L->tail = NULL;
return 1;
}
Node * pos = L->head;
while (pos != NULL && pos->next != node) {
pos = pos->next;
}
if (pos->next = node) {
if (node == L->tail)
L->tail = pos;
pos->next = pos->next->next;
return 1;
}
fprintf(stderr, "No such node in linked list.\n");
return 0;
}
int single_linked_list_reverse(SLL * L) {
if (L->head == NULL) {
fprintf(stderr, "The single linked list is empty.\n");
return 0;
}
L->tail = L->head;
Node *pre, *current, *next;
pre = L->head;
current = L->head->next;
L->head->next = NULL;
next = NULL;
while (current != NULL) {
next = current->next;
current->next = pre;
pre = current;
current = next;
}
L->head = pre;
return 1;
}
//------------------------------------------------------------------------


各个函数的功能均可见其函数名与返回值。使用SLL时动态分配内存即可,如:

void test_for_single_linked_list() {
SLL * L = (SLL*)malloc(sizeof(SLL));
printf("%p\n", L->head);
item_t item = {10, NULL};
Node * node;
for (int i = 0; i < 10; i++) {
item.key = i + 10;
single_linked_list_insert(L, item);
}
printf("SLL head is in location:%p\n", L->head);
linked_list_traverse(L->head);
single_linked_list_reverse(L);
linked_list_traverse(L->head);
for (int i = -1; i <= 10; i++) {
item.key = i + 10;
node = single_linked_list_search(L, item);
if (node != NULL)
printf("Node %d in location %p delete :%d\n", node->item.key, node, \
single_linked_list_delete(L, node));
//printf("SLL tail is in location:%p\n", L->tail);
}
printf("---------------------------------------------\n");
for (int i = 0; i < 10; i++) {
item.key = i + 10;
single_linked_list_insert(L, item);
}
printf("SLL head is in location:%p\n", L->head);
linked_list_traverse(L->head);
for (int i = 11; i >= -1; i--) {
item.key = i + 10;
node = single_linked_list_search(L, item);
if (node != NULL)
printf("Node %d in location %p delete :%d\n", node->item.key, node, \
single_linked_list_delete(L, node));
//printf("SLL tail is in location:%p\n", L->tail);
}
linked_list_free(L->head);
free(L);
}


双链接的未排序非循环链表可如如下实现:

//functions for double linked list
Node* double_linked_list_insert(DLL * L, item_t item) {
Node * node = (Node*)malloc(sizeof(Node));
node->prev = NULL;
node->item = item;
node->next = L->head;
if (L->head != NULL)
L->head->prev = node;
else
L->tail = node;
L->head = node;
return node;
}
Node* double_linked_list_search(DLL * L, item_t item) {
if (L->head == NULL) {
fprintf(stderr, "The double linked list is empty.\n");
return NULL;
}
Node * pos = L->head;
while (pos != NULL) {
if (pos->item.key == item.key)
return pos;
pos = pos->next;
}
fprintf(stderr, "The item cannot be found.\n");
return NULL;
}
int double_linked_list_delete(DLL * L, Node * node) {
if (L->head == NULL) {
fprintf(stderr, "The double linked list is empty.\n");
return 0;
}
if (node == NULL) {
fprintf(stderr, "The node is NULL.\n");
return 0;
}
if (node == L->tail)
L->tail = node->prev;
if (node->prev != NULL) {
node->prev->next = node->next;
} else {
L->head = node->next;
}
if (node->next != NULL) {
node->next->prev = node->prev;
}
return 1;
}
//----------------------------------------------------------------------------


注意要点与单链接的未排序非循环链表相同。测试可如下:

void test_for_double_linked_list() {
DLL * L = (DLL*)malloc(sizeof(DLL));
printf("%p\n", L->head);
item_t item = {10, NULL};
Node * node;
for (int i = 0; i < 10; i++) {
item.key = i + 10;
double_linked_list_insert(L, item);
}
printf("DLL head is in location:%p\n", L->head);
linked_list_traverse(L->head);
for (int i = -1; i <= 10; i++) {
item.key = i + 10;
node = double_linked_list_search(L, item);
if (node != NULL)
printf("Node %d in location %p delete :%d\n", node->item.key, node, \
double_linked_list_delete(L, node));
//printf("DLL tail is in location:%p\n", L->tail);
}
printf("---------------------------------------------\n");
for (int i = 0; i < 10; i++) {
item.key = i + 10;
double_linked_list_insert(L, item);
}
printf("DLL head is in location:%p\n", L->head);
linked_list_traverse(L->head);
for (int i = 11; i >= -1; i--) {
item.key = i + 10;
node = double_linked_list_search(L, item);
if (node != NULL)
printf("Node %d in location %p delete :%d\n", node->item.key, node, \
double_linked_list_delete(L, node));
//printf("DLL tail is in location:%p\n", L->tail);
}
linked_list_free(L->head);
free(L);
}


单链接未排序的循环链表可如如下实现:

//functinos for circular single linked list
Node* circular_single_linked_list_insert(CSLL * L, item_t item) {
Node * node = (Node*)malloc(sizeof(Node));
node->item = item;
node->prev = NULL;
if (L->head == NULL) {
L->head = node;
L->tail = node;
node->next = node;
} else {
node->next = L->head;
L->head = node;
L->tail->next = node;
}
return node;
}
Node* circular_single_linked_list_search(CSLL * L, item_t item) {
if (L->head == NULL) {
fprintf(stderr, "The circular single linked list is empty.\n");
return NULL;
}
Node * pos = L->head;
if (pos->item.key == item.key)
return pos;
else
pos = pos->next;
while (pos->item.key != item.key && pos != L->head) {
pos = pos->next;
}
if (pos != L->head)
return pos;
fprintf(stderr, "The item cannot be found.\n");
return NULL;
}
int circular_single_linked_list_delete(CSLL * L, Node * node) {
if (L->head == NULL) {
fprintf(stderr, "The circular single linked list is empty.\n");
return 0;
}
if (node == NULL) {
fprintf(stderr, "The node is NULL.\n");
return 0;
}
if (node == L->head && node == L->tail) {
L->head = NULL;
L->tail = NULL;
return 1;
} else if (node == L->head) {
L->head = node->next;
L->tail->next = L->head;
return 1;
}
Node * pos = L->head;
while (pos->next != node && pos != L->tail) {
pos = pos->next;
}
if (pos->next == node) {
if (node == L->tail) {
L->tail = pos;
}
pos->next = node->next;
return 1;
}
fprintf(stderr, "No such node in linked list.\n");
return 0;
}
//------------------------------------------------------------------------


测试可如下:

void test_for_circular_single_linked_list() {
CSLL * L = (CSLL*)malloc(sizeof(CSLL));
printf("%p\n", L->head);
item_t item = {10, NULL};
Node * node;
for (int i = 0; i < 10; i++) {
item.key = i + 10;
circular_single_linked_list_insert(L, item);
}
printf("CSLL head is in location:%p\n", L->head);
linked_list_traverse(L->head);
for (int i = -1; i <= 10; i++) {
item.key = i + 10;
node = circular_single_linked_list_search(L, item);
if (node != NULL)
printf("Node %d in location %p delete :%d\n", node->item.key, node, \
circular_single_linked_list_delete(L, node));
//linked_list_traverse(L->head);
}
printf("---------------------------------------------\n");
for (int i = 0; i < 10; i++) {
item.key = i + 10;
circular_single_linked_list_insert(L, item);
}
printf("CSLL head is in location:%p\n", L->head);
linked_list_traverse(L->head);
for (int i = 11; i >= -1; i--) {
item.key = i + 10;
node = circular_single_linked_list_search(L, item);
if (node != NULL)
printf("Node %d in location %p delete :%d\n", node->item.key, node, \
circular_single_linked_list_delete(L, node));
}
linked_list_free(L->head);
free(L);
}


有哨兵的双链接未排序循环链表可如如下实现:

//functions for cicular double linked list with sentinel
CDLLS* circular_double_linked_list_with_sentinel_init() {
CDLLS * L = (CDLLS*)malloc(sizeof(CDLLS));
L->nil = (Node*)malloc(sizeof(Node));
L->nil->next = L->nil;
L->nil->prev = L->nil;
return L;
}
Node* circular_double_linked_list_with_sentinel_insert(CDLLS * L, item_t item) {
Node * node = (Node*)malloc(sizeof(Node));
node->item = item;
node->next = L->nil->next;
L->nil->next->prev = node;
node->prev = L->nil;
L->nil->next = node;
return node;
}
Node* circular_double_linked_list_with_sentinel_search(CDLLS * L, item_t item) {
if (L->nil->next == L->nil) {
fprintf(stderr, "The circular double linked list is empty.\n");
return NULL;
}
Node* pos = L->nil->next;
while (pos != L->nil && pos->item.key != item.key) {
pos = pos->next;
}
if (pos == L->nil) {
fprintf(stderr, "The item cannot be found.\n");
return NULL;
} else {
return pos;
}
}
int circular_double_linked_list_with_sentinel_delete(CDLLS * L, Node * node) {
if (L->nil->next == L->nil) {
fprintf(stderr, "The circular double linked list is empty.\n");
return 0;
}
if (node == NULL) {
fprintf(stderr, "The node is NULL.\n");
return 0;
}
node->prev->next = node->next;
node->next->prev = node->prev;
return 1;
}
//--------------------------------------------------------------------------


测试可如下:

void test_for_circular_double_linked_list() {
CDLLS * L = circular_double_linked_list_with_sentinel_init();
printf("%p %p %p %p\n", L, L->nil, L->nil->prev, L->nil->prev);
item_t item = {10, NULL};
Node * node;
for (int i = 0; i < 10; i++) {
item.key = i + 10;
circular_double_linked_list_with_sentinel_insert(L, item);
}
printf("CDLLS nil is in location:%p\n", L->nil);
linked_list_traverse(L->nil);
for (int i = -1; i <= 10; i++) {
item.key = i + 10;
node = circular_double_linked_list_with_sentinel_search(L, item);
if (node != NULL)
printf("Node %d in location %p delete :%d\n", node->item.key, node, \
circular_double_linked_list_with_sentinel_delete(L, node));
}
printf("---------------------------------------------\n");
for (int i = 0; i < 10; i++) {
item.key = i + 10;
circular_double_linked_list_with_sentinel_insert(L, item);
}
printf("CDLLS nil is in location:%p\n", L->nil);
linked_list_traverse(L->nil);
for (int i = 11; i >= -1; i--) {
item.key = i + 10;
node = circular_double_linked_list_with_sentinel_search(L, item);
if (node != NULL)
printf("Node %d in location %p delete :%d\n", node->item.key, node, \
circular_double_linked_list_with_sentinel_delete(L, node));
}
linked_list_free(L->nil);
free(L);
}


可以将其看为含有哨兵的一个循环的圆圈,这样理解比较方便。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言 链表