前言:
单链表是基础的数据结构, 分为有头结点和无头结点, 无头结点使用起来比较麻烦, 下面是有头结点的单链表操作, 重点是在于有头结点的单链表翻转操作。
代码:singlelist.c
/* 带头结点head的单链表 */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <assert.h> #include "list.h" NODE *head = NULL; /* 翻转链表(递归方法) */ NODE* reverse_list_recursion(NODE *pNode) { if(NULL == pNode || NULL == pNode->next) return pNode; NODE *newhead = reverse_list_recursion(pNode->next); if(pNode != head){ pNode->next->next = pNode; pNode->next = NULL;
return newhead; } else { pNode->next = newhead;
return pNode; } } /* 尾插法插入节点到链表 1:首先需要找到尾结点, 它的标志就是next域为NULL 2:创建新结点初始化 3:尾结点的next域指向新结点 */ void tail_insert_node(NODE *head, int data) { NODE *tail = head; while(tail->next != NULL) tail = tail->next; NODE *p = (NODE *)calloc(1, sizeof(struct list)); p->data = data; p->next = NULL; tail->next = p; } /* 头插法插入结点到链表, 比尾插法简单, 不需要找到尾结点 1:创建新结点, 新结点的next指向头结点的next 2:头结点的next域指向新结点 */ void head_insert_node(NODE *head, int data) { NODE *p = (NODE *)calloc(1, sizeof(struct list)); p->data = data; p->next = head->next; head->next = p; } /* 尾插法初始化链表 */ void init_list_tail(NODE *head) { int array[5] = {1, 2, 3, 4, 5}; int i; assert(head); for(i=0; i<(sizeof array)/(sizeof array[0]); i++) { tail_insert_node(head, array[i]); } } /* 头插法初始化链表 */ void init_list_head(NODE *head) { int array[5] = {1, 2, 3, 4, 5}; int i; assert(head); for(i=0; i<(sizeof array)/(sizeof array[0]); i++) { head_insert_node(head, array[i]); } } /* 删除一个结点 */ void remove_list_node(NODE *head, int data) { if(NULL == head || NULL == head->next){ printf("Already empty list\n"); return; } NODE *pNode = head; NODE *ptr = NULL; while(pNode->next != NULL){ if(pNode->next->data != data) { pNode = pNode->next; continue; } else { ptr = pNode->next; pNode->next = pNode->next->next; free(ptr); return; } } printf("no this node in list\n"); } void print_list(NODE *head) { NODE *p = head->next; int i = 0; while(p){ printf("list[%d]:%d\n", i++, p->data); p = p->next; } } int main(int argc, char const *argv[]) { head = (NODE *)calloc(1, sizeof(struct list)); init_list_tail(NULL); print_list(head); reverse_list_recursion(head); print_list(head); remove_list_node(head, 5); head = reverse_list_recursion(head); print_list(head); return 0; }
list.h
#ifndef __LIST_H__ #define __LIST_H__ typedef struct list { int data; struct list *next; }NODE; NODE* reverse_list_recursion(NODE *pNode); void tail_insert_node(NODE *head, int data); void head_insert_node(NODE *head, int data); void init_list_tail(NODE *head); void init_list_head(NODE *head); void print_list(NODE *head); #endif
翻转单链表的函数:
NODE* reverse_list_recursion(NODE *pNode) { if(NULL == pNode || NULL == pNode->next) return pNode; NODE *newhead = reverse_list_recursion(pNode->next); if(pNode != head){ pNode->next->next = pNode; pNode->next = NULL;
return newhead; } else { pNode->next = newhead;
return pNode; } }
使用了递归的思想, 可以把单链表看做只有左子树的树, 依次递归交换相邻两个树叶的指向。head是全局的头结点, 但是要判断一种特殊情况, 那就是pNode回归最后指向了head时(此时也是递归最后一次), 这时候就不要交换head和第一个结点的指向了, 只需要将head的next指向新的第一个结点newhead就可以了。