曾經的筆記遷移__通用鏈表網絡版

C通用鏈表庫(1.0版) 
轉載自網絡。
 
本鏈表庫可以使用CodeBlocks(MingW)和VC系列編譯器進行編譯,爲單向帶頭尾的鏈表,封裝後使用起來很簡單,實現了鏈表的增,刪,改,排序,清空,遍歷等常用操作,可進行元素的前插和尾插,還有兩個功能,插入排序和清除重複元素,準備在下一版實現。
頭文件:list.h
#ifndef LIST_H_H
#define LIST_H_H
#include <stdio.h>
#include <malloc.h>
#include <string.h>
typedef struct clist *List;
typedef int (*compare)(void *ndata, void *data);
typedef void (*dofunc)(void *ndata);
typedef int (*lpf0)(List l, void *data);
typedef int (*lpf1)(List l, void *data, compare pfunc);
typedef List (*lpf2)(List l);
typedef void (*lpf3)(List l);
typedef void (*lpf4)(List l, dofunc pfunc);
typedef int (*lpf5)(List l, unsigned int index, void *new_data);
typedef void (*lpf6)(List l, compare pfunc);
typedef int (*lpf7)(List l, unsigned int index);
typedef struct cnode
{
 void *data;
 struct cnode *next;
}node, *Node;
typedef struct clist
{
 Node head;
 Node tail;
 unsigned int size;
 unsigned int data_size;
 lpf0 add_back;
 lpf0 add_front;
 lpf1 delete_node;
 lpf1 have_same;
 lpf4 foreach;
 lpf3 clear;
 lpf2 destroy;
 lpf5 modify_at;
 lpf6 sort;
 lpf7 delete_at;
}list;
//初始化鏈表
List list_init(unsigned int data_size);        
int  list_add_back(List l, void *data);
int  list_add_front(List l, void *data);
int  list_delete_node(List l, void *data, compare pfunc);
int  list_delete_at(List l, unsigned int index);
int  list_modify_at(List l, unsigned int index, void *new_data);
int  list_have_same(List l, void *data, compare pfunc);
void list_foreach(List l, dofunc doit);
void list_sort(List l, compare pfunc);
void list_clear(List l);
//釋放鏈表
List list_destroy(List l);
#endif
----------------------------------------------------------------------------------------------------------------------------------------
實現文件:list_impl.c
#include "list.h"
/// 文件:list_impl.c
/// 功能:實現鏈表的基本操作
/// 作者:bluewind
/// 完成時間:2011.5.29
/// 修改時間:2011.5.31, 2011.7.2
/// 修改備註:在頭節點處添加一個空節點,可以優化添加、刪除節點代碼
///  再次修改,鏈表增加節點數據data_size,限制數據大小,修改了
///  添加複製數據代碼,修正重複添加節點後釋放節點的Bug,添加了前
///  插、排序和遍歷功能,7.3 添加tail尾指針,改進後插法性能,並改名
/// --------------------------------------------------------------
void swap_data(Node n1, Node n2);
/// --------------------------------------------------------------
//  函數名:list_init
//  功能:  鏈表初始化
//  參數:  無 
//  返回值:已初始化鏈表指針
//  備註:  鏈表本身動態分配,由list_destroy函數管理釋放
/// --------------------------------------------------------------
List list_init(unsigned int data_size)
{
 List list = (List) malloc(sizeof(struct clist));
 if(list != NULL)                                        //內存分配成功
 {
  list->head = (Node) malloc(sizeof(node));           //爲頭節點分配內存
  if(list->head)          //內存分配成功
  {
   list->head->data = NULL;      //初始化頭節點
   list->head->next = NULL;
   list->data_size  = data_size;
   list->tail = list->head;
   list->size = 0;
   
   list->add_back  = list_add_back;   //初始化成員函數
   list->add_front  = list_add_front;
   list->delete_node = list_delete_node;
   list->delete_at  = list_delete_at;
   list->modify_at  = list_modify_at;
   list->have_same  = list_have_same;
   list->foreach  = list_foreach;
   list->clear   = list_clear;
   list->sort   = list_sort;
   list->destroy  = list_destroy;
  }
 }
 return list;
}
/// --------------------------------------------------------------
//  函數名:list_add_back
//  功能:  添加鏈表結點 (後插法)
//  參數:  l--鏈表指針,data--鏈表數據指針,可爲任意類型 
//  返回值:int型,爲1表示添加成功,爲0表示添加失敗
//  備註:  如果鏈表本身爲空或是分配節點內存失敗,將返回0
/// --------------------------------------------------------------
int  list_add_back(List l, void *data)
{
 Node new_node = (Node) malloc(sizeof(node));
 
 if(l != NULL && new_node != NULL)  //鏈表本身不爲空,且內存申請成功
 {
  new_node->data = malloc(l->data_size);
  memcpy(new_node->data, data, l->data_size);
  new_node->next = NULL;
  l->tail->next = new_node;   //添加節點
  l->tail = new_node;     //記錄尾節點位置
  l->size ++;       //鏈表元素總數加1
  
  return 1;
 }
 
 return 0;
}
/// --------------------------------------------------------------
//  函數名:list_add_front
//  功能:  添加鏈表結點 (前插法)
//  參數:  l--鏈表指針,data--鏈表數據指針,可爲任意類型 
//  返回值:int型,爲1表示添加成功,爲0表示添加失敗
//  備註:  如果鏈表本身爲空或是分配節點內存失敗,將返回0
/// --------------------------------------------------------------
int list_add_front(List l, void *data)
{
 Node new_node = (Node) malloc(sizeof(node));
 
 if(l != NULL && new_node != NULL)
 {
  new_node->data = malloc(l->data_size);
  memcpy(new_node->data, data, l->data_size);
  new_node->next = l->head->next;
  l->head->next = new_node;
  if(!l->size)        //記錄尾指針位置
   l->tail = new_node;
  l->size ++;
  
  return 1;
 }
 
 return 0;
}
/// --------------------------------------------------------------
//  函數名:list_delete_node
//  功能:刪除鏈表結點
//  參數:l--鏈表指針,data--鏈表數據指針,可爲任意類型
//        *pfunc爲指向一個數據類型比較的函數指針
//  返回值:int型,爲1表示刪除成功,爲0表示沒有找到匹配數據
//  備註:*pfunc函數接口參數ndata爲節點數據,data爲比較數據,返回爲真表示匹配數據
/// --------------------------------------------------------------
int  list_delete_node(List l, void *data, int (*pfunc)(void *ndata, void *data))
{
 if(l != NULL)
 {
  Node prev = l->head;      //前一個節點
  Node curr = l->head->next;     //當前節點
  
  while(curr != NULL)
  {
   if(pfunc(curr->data, data))    //如果找到匹配數據
   {
    if(curr == l->tail)     //如果是刪除尾節點
     l->tail = prev;
    prev->next = prev->next->next;  //修改前節點next指針指向下下個節點
    
    free(curr->data);     //釋放節點數據
    free(curr);       //釋放節點
    
    l->size--;       //鏈表元素總數減1
    return 1;       //返回真值
   }
   prev = prev->next;      //沒有找到匹配時移動前節點和當前節點
   curr = curr->next;
  }
 }
 
 return 0;         //沒有找到匹配數據
}
/// --------------------------------------------------------------
//  函數名:list_delete_at
//  功能:  修改鏈表節點元素值
//  參數:  l--鏈表指針,index--索引值, 範圍(0 -- size-1) 
//  返回值:int型,爲1表示刪除成功,爲0表示刪除失敗
//  備註:  如果鏈表本身爲空或是index爲非法值,將返回0
/// --------------------------------------------------------------
int list_delete_at(List l, unsigned int index)
{
 unsigned int cindex = 0;
 if(l != NULL && index >= 0 && index < l->size)
 {
  Node prev = l->head;      //前一個節點
  Node curr = l->head->next;     //當前節點
  
  while(cindex != index)
  {
   prev = prev->next;
   curr = curr->next;
   cindex ++;
  }
  if(index == (l->size) - 1)
   l->tail = prev;
  prev->next = prev->next->next;
  free(curr->data);
  free(curr);
  l->size --;
  return 1;
 }
 return 0;
}
/// --------------------------------------------------------------
//  函數名:list_modify_at
//  功能:  修改鏈表節點元素值
//  參數:  l--鏈表指針,index--索引值, 範圍(0 -- size-1) 
//   data--鏈表數據指針
//  返回值:int型,爲1表示修改成功,爲0表示修改失敗
//  備註:  如果鏈表本身爲空或是index爲非法值,將返回0
/// --------------------------------------------------------------
int list_modify_at(List l, unsigned int index, void *new_data)
{
 unsigned int cindex = 0;
 if(l != NULL && index >= 0 && index < l->size )  //非空鏈表,並且index值合法
 {
  Node curr = l->head->next;
  while(cindex != index)
  {
   curr = curr->next;
   cindex ++;
  }
  memcpy(curr->data, new_data, l->data_size);
  return 1;
 }
 return 0;
}
/// --------------------------------------------------------------
//  函數名:list_sort
//  功能:  鏈表排序
//  參數:  l--鏈表指針,*pfunc爲指向一個數據類型比較的函數指針
//  返回值:無
//  備註:  使用簡單選擇排序法,相比冒泡法每次交換,效率高一點
/// --------------------------------------------------------------
void list_sort(List l, compare pfunc)
{
 if(l != NULL)
 {
  Node min, icurr, jcurr;
  icurr = l->head->next;
  while(icurr)
  {
   min = icurr;        //記錄最小值
   jcurr = icurr->next;      //內循環指向下一個節點
   while(jcurr)
   {
    if(pfunc(min->data, jcurr->data))  //如果找到n+1到最後一個元素最小值
     min = jcurr;      //記錄下最小值的位置
    jcurr = jcurr->next;
   }
   if(min != icurr)       //當最小值位置和n+1元素位置不相同時
   {
    swap_data(min, icurr);     //才進行交換,減少交換次數
   }
   icurr = icurr->next;
  }
 }
}
void swap_data(Node n1, Node n2)
{
 void *temp;
 temp = n2->data;
 n2->data = n1->data;
 n1->data = temp;
}


int list_have_same(List l, void *data, int (*pfunc)(void *ndata, void *data))
{
 if(l != NULL)
 {
  Node curr;
  for(curr = l->head->next; curr != NULL; curr = curr->next)
  {
   if(pfunc(curr->data, data))
   {
    return 1;
   }
  }
 }
 return 0;
}
/// --------------------------------------------------------------
//  函數名:list_foreach
//  功能:  遍歷鏈表元素
//  參數:  l--鏈表指針,doit爲指向一個處理數據的函數指針 
//  返回值:無
//  備註:  doit申明爲void (*dofunc)(void *ndata)原型
/// --------------------------------------------------------------
void list_foreach(List l, dofunc doit)
{
 if(l != NULL)
 {
  Node curr;
  for(curr = l->head->next; curr != NULL; curr = curr->next)
  {
   doit(curr->data);
  }
 }
}
/// --------------------------------------------------------------
//  函數名:list_clear
//  功能:  清空鏈表元素
//  參數:  l--鏈表指針
//  返回值:無
// 備註: 沒有使用先Destroy再Init鏈表的辦法,直接實現
/// --------------------------------------------------------------
void list_clear(List l)
{
 if(l != NULL)
 {
  Node temp;
  Node curr = l->head->next;
  while(curr != NULL)
  {
   temp = curr->next; 
   
   free(curr->data);    //釋放節點和數據
   free(curr);
   
   curr = temp;
  }
  l->size = 0;      //重置鏈表數據
  l->head->next = NULL;
  l->tail = l->head;
 }
}
/// --------------------------------------------------------------
//  函數名:list_destroy
//  功能:  釋放鏈表
//  參數:  l--鏈表指針
//  返回值:空鏈表指針
/// --------------------------------------------------------------
List list_destroy(List l)
{
 if(l != NULL)
 {
  Node temp;
  while(l->head)
  {
   temp = l->head->next;
   
   if(l->head->data != NULL)   //如果是頭節點就不釋放數據空間
    free(l->head->data);   //先釋放節點數據(但是節點數據裏也有指針?)
   free(l->head);      //再釋放節點
   
   l->head = temp;
  }
  free(l);        //釋放鏈表本身佔用空間
  l = NULL;
 }
 return l;
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------
測試用例:main.c
#include "..\list.h"
#include <stdio.h>
typedef struct tag_msg
{
        int x;
}msg, *Msg;
typedef struct foo
{
 char a;
 char b;
 char c;
 char d;
 char e;
}Foo, *Pfoo;
int compare_data(void *ndata, void *data);
void show_data(void *ndata);
int compare2(void *ndata, void *data);
int main()
{
        List list = NULL;
        Node current;
        Msg m1, m2, m3, m4, m5;
  msg m6;
  Foo f1;
        unsigned int i;
  unsigned int data_size;
        
  data_size = sizeof(msg);
        list = list_init(data_size);
        
        m1 = (Msg) malloc(sizeof(msg));
        m2 = (Msg) malloc(sizeof(msg));
        m3 = (Msg) malloc(sizeof(msg));
        m4 = (Msg) malloc(sizeof(msg));
        m5 = (Msg) malloc(sizeof(msg));
        
        m1->x = 100;
        m2->x = 200;
        m3->x = 300;
        m4->x = 400;
        m5->x = 500;
  m6.x  = 600;
  f1.a = 2;
  f1.b = 1;
  f1.c = 0;
  f1.d = 0;
  f1.e = 0;
        
        //添加測試
  list->add_front(list, m1);
  list->add_front(list, m2);
  list->add_front(list, m3);
  list->add_front(list, m4);
  list->add_back(list, m2);
  list->add_back(list, m3);
  list->add_back(list, &m6);
  list->add_back(list, &f1);
  free(m1);
        current = list->head->next;
        for(i = 0; i < (list->size); i++)
        {
                printf("data of msg is %d\n", 
                        ((Msg)(current->data))->x);
                
                current = current->next;
        }
        
        //刪除測試
        if(list_delete_node(list, &m6, compare_data))
        {
                printf("\nDelete node OK!\n");
        }
        else
        {
                printf("\nNode data not found!\n");
        }
  list->add_back(list, m4);
  //清空測試
  //list->clear(list);
  //修改測試
  if(list->modify_at(list, 6, m2))
  {
   printf("\nModity data OK!\n\n");
  }
  else
  {
   printf("\nModify data faile!\n\n");
  }
  //list_delete_at(list, 0);
  //list->add_back(list, m2);
  list->add_back(list, &m6);
  list->add_front(list, &f1);
  list->add_back(list, &f1);
       
  list->foreach(list, show_data);        
        
  //排序測試
  list_sort(list, compare2);
  printf("sort after:\n");
  list->foreach(list, show_data);
        list_destroy(list);
        
  free(m4);
        free(m5);
        
        return 0;
}
//實現數據比較
int compare_data(void *ndata, void *data)
{
        if(((Msg)(ndata))->x == ((Msg)(data))->x)
        {
                return 1;
        }
        return 0;
}
int compare2(void *ndata, void *data)
{
 if( ((Msg)ndata)->x > ((Msg)data)->x )
  return 1;
 return 0;
}
//實現遍歷數據, 用於list->foreach
void show_data(void *ndata)
{
 printf("data of msg is %d\n", 
                        ((Msg)(ndata))->x);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章