直接贴上已经码好的:
list_sort.c:
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
/**** 双向链表,非双向循环链表哦!
*
* gcc -m32 : 在64位系统上编译出32位的程序(指针大小4字节),
* 这样编译本代码不会编译报警告
*
*****/
#define use_double_direction_list //关闭双向非循环链表模式,则默认开启单向非循环链表模式
/*计算member在type中的位置*/
#define offsetof(type, member) (unsigned int)(&((type*)0)->member)
/*根据member的地址获取type的起始地址*/
#define container_of(ptr, type, member) ({
const typeof(((type *)0)->member)*__mptr = (ptr);
(type *)((char *)__mptr - offsetof(type, member)); })
typedef struct _inside_link{
struct _inside_link* pNext;
#if defined(use_double_direction_list)
struct _inside_link* pFront;
#endif
}inside_link;
typedef struct _usr_data_pack{
unsigned char* name0;
unsigned int data0;
}usr_data_pack;
typedef struct _usrdata_templ{
inside_link link;
usr_data_pack usr_data;
}usrdata_templ;
void usrdata_set(usrdata_templ* pusr_data_list, usr_data_pack* pdata_pack){
memset(&pusr_data_list->usr_data, 0, sizeof(usr_data_pack));
memcpy(&pusr_data_list->usr_data, pdata_pack, sizeof(usr_data_pack));
}
static void print_usr_data_pack(usr_data_pack* pdata_pack){
printf("pdata_pack->name0 = 33[0;31m %s, 33[0m pdata_pack->data0 = 33[0;33m %d 33[0m
",
pdata_pack->name0, pdata_pack->data0);
}
void usrdata_print(usrdata_templ* pusr_data_list){
if(pusr_data_list != NULL){
print_usr_data_pack(&pusr_data_list->usr_data);
}
inside_link* pNext_link = pusr_data_list->link.pNext;
while(pNext_link){
usrdata_templ* pNext_templ = NULL;
pNext_templ = container_of(pNext_link, usrdata_templ, link);
print_usr_data_pack(&pNext_templ->usr_data);
pNext_link = pNext_link->pNext;
}
}
void link_init(inside_link* plink){
#if defined(use_double_direction_list)
plink->pFront = NULL;
#endif
plink->pNext = NULL;
}
/***** 对比内核链表
下面是内核从尾部添加函数:
static inline void list_add_tail(struct list_head *newer, struct list_head *head)
{
__list_add(newer, head->prev, head);
}
内核链表使用了双向循环链表,这里找到尾巴节点,只要从头节点向前推一个节点就找到了,很方便。
而我使用了双向非循环链表,就需要遍历了,代码也更难看了。
心得: 双向循环链表相对于双向非循环链表,几乎不增加内存成本,而且能够提高效率。
以后写代码,编写组件,都要使用双向循环链表。
*******/
/**
* list_add_tail没有检查同一个链表节点两次被加入的情况。
* 但是我这个函数检查了
* **/
int link_tail_add(inside_link* plink, inside_link* pnode){
inside_link* pcurrent_node = plink->pNext;
inside_link* pformer_node = plink;
if(plink == pnode){ /****检查同一个链表节点两次及以上次数被加入*****/
return -1;
}
while(pcurrent_node){
if(pnode == pcurrent_node){ /****检查同一个链表节点两次及以上次数被加入*****/
return -1;
}
pformer_node = pcurrent_node;
pcurrent_node = pcurrent_node->pNext;
}
#if defined(use_double_direction_list)
pnode->pFront = pformer_node;
#endif
pformer_node->pNext = pnode;
return 0;
}
void create_usrdaralist1(usrdata_templ* phead){
link_init(&phead->link);
// add first node, then print
usr_data_pack pack0 = {"jack 170", 170};
usrdata_set(phead, &pack0);
#if 0
// add second node, then print
usrdata_templ* pnode1 = (usrdata_templ*)malloc(sizeof(usrdata_templ));
usr_data_pack pack1 = {"jack 171", 171};
link_init(&pnode1->link);
usrdata_set(pnode1, &pack1);
if(!link_tail_add(&phead->link, &pnode1->link)){
}else{
printf("