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;
}
相关文章
相关标签/搜索