C語言泛型初探----C鏈表

C語言泛型,能夠仿照 C庫函數 qsort 的方式node

用戶提供 一些回調函數。算法

數據結構不包含數據域,數據結構

數據域 由分配節點內存的時候,多分配一些空間提供函數

數據域的地址:  spa

節點指針 是 p,則數據域地址爲 p+1;指針

下面,是個簡單的單鏈表實現code

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

////類型定義

typedef struct LNode{
	struct LNode *next;
}*PLNode,*List;

/// 裸節點大小
enum{NodeOnlySize =(sizeof(struct LNode))};

#define NodeSize(elmSize) (NodeOnlySize + elmSize) ////節點大小,跟元素大小相關

#define GetElem(type,p)  (*(type*)(void *)(p + 1))  //// 取節點元素

////////////////////////////////////////////////////////
//// 回調函數定義

//// 1)複製函數,用於複製元素數據。

//// 2)釋放函數,用於釋放元素內部數據。

typedef void* (*copy_elm)(void *elm,const void *data,size_t elmsize);

typedef void (*free_elm)(void *elm);



////產生無數據節點,能夠私有化
PLNode GenNode(int elmSize){
	PLNode p = malloc(NodeSize(elmSize));
	p->next =NULL;
	return p;
}

//// 建立節點
PLNode CreateNode(copy_elm cpy,void *data,int elmSize){
	PLNode p =GenNode(NodeSize(elmSize));
	cpy(p + 1,data,elmSize);
	return p;
}

/// 建立鏈表,建立一個只有表頭節點的鏈表
List Create(int elmSize){
	return  GenNode(NodeSize(elmSize));
}

///批量插入數據,批量前插
List insertFrontBulk(List lst,copy_elm cpy, int n,void *d,int elmSize){
	PLNode p;
	int i;
	if(!lst)
	  return NULL;
	for(i=0;i<n;i++){
		p = CreateNode(cpy,d+i,elmSize);
		p ->next =lst ->next;
		lst->next = p;
	}
	return lst;
}



///前插
List insertFront(List lst,copy_elm cpy, void *d,int elmSize){
	PLNode p;
	if(!lst)
	  return NULL;
	p = CreateNode(cpy,d,elmSize);
	p ->next =lst ->next;
	lst->next = p;
	return lst;
}

///批量插入數據,批量後插
List insertBackBulk(List lst,int n,copy_elm cpy, void *d,int elmSize){
	PLNode p=lst,q;
	int i;
	if(!p)return NULL;
	while(p->next){
		p =p->next;
	}
	for(i=0;i<n;i++){
		q = CreateNode(cpy,d+i,elmSize);
		q ->next =p ->next;
		p->next = q;
	}
	return lst;
}

///後插

List insertBack(List lst,copy_elm cpy, void *d,int elmSize){
	PLNode p=lst,q;
	if(!p)return NULL;
	while(p->next){
		p =p->next;
	}


	q = CreateNode(cpy,d,elmSize);
	q ->next =p ->next;
	p->next = q;
	return lst;
}


/// 銷燬鏈表
void Destory(List lst,free_elm fre){
	PLNode p =lst,q;
	if(!lst)return ;
	p = lst->next;


	while(p){


		q = p;
		p = p->next;
		if(fre)
		  fre(&q->next+1);
		free(q);
	}
	free(lst);
}




///實現數據複製
void *copyint(void *dst,const void *src,size_t n){
	*(int *)dst = *(int*)src;
	return dst;
}


int main()
{
	int n=10;
	const int elmSize = sizeof(int);
	List L =Create(elmSize);
	PLNode p ;


	while(n>0){
		///insertFront(L,memcpy,&n,elmSize);
		insertBack(L,memcpy,&n,elmSize);
		--n;
	}


	p = L;
	while(p = p->next){
		printf("data =%d\n", GetElem(int,p));
	}

	Destory(L,NULL);

	printf("Hello world!\n");
	getchar();
	return 0;
}

雙向鏈表:blog

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -內存

和單向鏈表相比有如下優點:element

插入刪除不須要移動元素外,能夠原地插入刪除

能夠雙向遍歷

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

初始化+尾插法圖示://head始終指向頭結點,p指向尾節點,方便後續算法使用

刪除單個圖示:

實現代碼:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node pNode;
struct Node
{
    int data;
    pNode *prev, *next;
};
/* 初始化鏈表,尾插法 */
pNode *InitList(pNode **head, int n)
{
    pNode *p, *s;
    (*head) = (pNode *)malloc(sizeof(pNode));
    if ((*head) == NULL)
        exit(0);
    (*head)->next = NULL;//head的prev和next均指向NULL
    (*head)->prev = NULL;
    p = (*head);//p指向head
    int i;
    for (i = 0; i < n; ++i)
    {
        s = (pNode *)malloc(sizeof(pNode));
        if (s == NULL)
            exit(0);
        printf("Input the value of the %dth node:", i + 1);
        scanf("%d", &s->data);
        s->next = NULL;
        p->next = s;
        s->prev = p;
        p = s;//p指向尾節點
    }
    return p;
}
/* 遍歷打印 */
void PrintList(pNode *head)
{
    pNode *p;
    p = head->next;
    if (head->next == NULL)
        printf("the list is empty\n");
    while(p != NULL)
    {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
}
/* 清空鏈表 */
void DeleteList(pNode **head)
{
    pNode *p;
    while((*head)->next != NULL)
    {
        p = (*head);
        p->next->prev = NULL;
        (*head) = p->next;
        free(p);
    }
}
/* 查找鏈表內的某個值 */
int SearchList(pNode *head)
{
    int number;
    printf("Values are about to be deleted:");
    scanf("%d", &number);
    pNode *p;
    p = head->next;
    while(p != NULL)
    {
        if (p->data == number)
        {
            return number;
        }
        p = p->next;
    }
    return 0;
}
/* 刪除鏈表中某個元素,令p的前驅節點和後驅節點相互指向便可,若是p是尾節點則直接將前驅節點指向NULL*/
void DelNumqList(pNode **head, int n)
{
    int i;
    pNode *p;
    p = (*head)->next;
    for (i = 1; i < n; ++i)
        p = p->next;
    if(p->next == NULL)
    {
        p->prev->next = NULL;
        free(p);
    }
    else
    {
        p->next->prev = p->prev;
        p->prev->next = p->next;
        free(p);
    }
}
int main(int argc, char const *argv[])
{
    int n, element, flag;
    pNode *head, *last;
    /***************************************************************/
    printf("Please input the size of the list:");
    scanf("%d", &n);
    last = InitList(&head, n);//初始化鏈表並賦值,返回尾節點last
    printf("%d %d \n", head->next->data, last->data); //打印爲第一個元素和最後一個元素
    PrintList(head);
    /***************************************************************/
    flag = SearchList(head); //搜索某個值並刪除節點
    if (flag > 0 && flag <= n)
    {
        DelNumqList(&head, flag);
        PrintList(head);
    }
    else
        printf("Element does not exist, cannot be deleted\n");
    /***************************************************************/
    DeleteList(&head);//清空列表
    PrintList(head);
    return 0;
}
相關文章
相關標籤/搜索