数据结构_链表

链表

类型:
单向链表:
双向链表:
- 双向链表的前向指针指向前一个结点的首地址,后向指针指向下一个节点的首地址,并且指针类型相同,且只能指向与自己类型相同的结构体。
循环链表:
通用链表:
- 通用链表的前向指针指向前一个结点的指针域的首地址,后向指针指向下一个节点的指针域的首地址,所以在不同的结构体中定义相同的指针域就可以了,也就是说,单独定义一个结构体类型,其成员只有指针域,并且在其他结构体中定义这种结构体类型的变量。

单向链表

  • 单向单指针操作
/*
 * 3_stu_input.c
现有学生结构体(id,name,score),写代码实现
(1)从键盘初始化学员
(2)使用链表
(3)遍历打印所有学员
 */


#include <stdio.h>
#include <stdlib.h>
#define SIZE 3
struct student
	{
		char name[20];
		int id;
		int score;
		struct student* next;
	};
typedef struct student stud;
void output(void);
void insert(void);
stud* creat(stud* p);

stud* head=NULL;

int main(void)
{
	head=creat(head);
	char n='\0';
	while(n!='q'){
		insert();
		printf("按任意键继续,或者按'q'退出:\n");
		while(getchar()!='\n');
		scanf("%c",&n);
		
	}
	printf("输入的学生信息为:\n");
	output();
	
	return 0;
}
stud* creat(stud* p){
	p=(stud*)malloc(sizeof(stud));
	p->next=NULL;
	return p;
}
	
void insert(void){
	stud* p=(stud*)malloc(sizeof(stud));
	printf("请输入学生的学号,名字和成绩:");
	scanf("%d %s %d",&p->id,p->name, &p->score);
	p->next=NULL;
	
	stud* current = head; 
	while(current->next!=NULL) current=current->next;
	current->next=p;

}

void output(void){
	for(stud* current=head; 
			current->next!=NULL; current=current->next)	
		printf("%d %s %d\n",current->next->id,current->next->name, current->next->score);
}//此处判断到结点指向NULL就会退出,无法输出最终项,所以使用current=head,current->next->name来输出。

双向链表

  • 链表结点数据结构定义
struct xLIST_ITEM
{
	TickType_t xItemValue;					//辅助值,用于帮助节点进行排序
	struct xLIST_ITEM* pxNext;			//指向链表下一个节点
	struct xLIST_ITEM* pxPrevious;		//指向链表上一个节点
	void* pvOwner;   //指向拥有该节点的对象
	void* pvContainer;  //指向该节点所在的链表
};
typedef struct xLIST_ITEM ListItem_t;
  • 链表节点初始化
void vListInitializeItem(ListItem_t* const pxItem)
{
	//初始化该节点所在链表为空,表示节点还未插入任何链表
	pxItem->pvContainer = NULL;
}
  • 链表根节点数据结构定义
typedef struct xList
{
	UBaseType_t uxNumberOfItems;	//链表节点计数器
	ListItem_t* pxIndex;	//链表节点索引指针
	MiniListItem_t xListEnd;	//链表最后一个节点
}List_t;
  • 链表精简节点结构体定义
struct xMINI_LIST_ITEM
{
	TickType_t xItemValue;					//辅助值,用于帮助节点进行排序
	struct xLIST_ITEM* pxNext;			//指向链表下一个节点
	struct xLIST_ITEM* pxPrevious;		//指向链表上一个节点
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;
  • 链表根节点的初始化
void vListInitialize(List_t* const pxList)
{
	//将链表索引指针指向最后一个节点
	pxList->pxIndex = (ListItem_t*) &(pxList->xListEnd);	
	
	//将链表最后一个节点的辅助排序值设置最大
	pxList->xListEnd.xItemValue = portMAX_DELAY;
	
	//将最后一个节点的next 和 previous指针均指向节点本身,表示链表为空
	pxList->xListEnd.pxNext = (ListItem_t*) &(pxList->xListEnd);	
	pxList->xListEnd.pxPrevious = (ListItem_t*) &(pxList->xListEnd);	
	
	//初始化链表计数器值为0,表示链表为空
	pxList->uxNumberOfItems = (UBaseType_t) 0U;
	
}

双向循环链表操作

/*双循环通用链表*/

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

typedef struct Link link_t;
 
struct Link
{
	void *data;
	link_t *pre;
	link_t *next;
};

link_t* creathead(void);
link_t* creatnode(void); 
link_t* insertnode(link_t *head, void *data, int size);
void display_link(link_t *head); 
void destroy_allnode(link_t *head); 

void sort_link(link_t *start, link_t *end, int (*cp)(const void *, const void *));
int compare(const void* p1, const void *p2);

int main(void)
{
	int data = 0;
	link_t *head = creathead();
	for (int i = 0; i < 10; i++){
		data = rand() % 100;
		insertnode(head, &data, sizeof(data));
	}
	
	display_link(head); 
	sort_link(head->next, head->pre, compare);
	display_link(head); 
	
	destroy_allnode(head);
	
	return 0;
}

link_t* creathead(void)
{
	link_t *head = NULL;
	head = (link_t*)malloc(sizeof(link_t)); 
	if (NULL == head){
		perror("malloc failed!");
		return NULL;
	}
	memset(head, 0, sizeof(link_t));
	head->pre = head;
	head->next = head;
	
	return head;
}

link_t* creatnode(void)
{
	link_t *p = NULL;
	p = (link_t*)malloc(sizeof(link_t)); 
	if (NULL == p){
		perror("malloc failed!");
		return NULL;
	}
	memset(p, 0, sizeof(link_t));
	
	return p;
}

//尾插
link_t* insertnode(link_t *head, void *data, int size)
{
	link_t *node = NULL;
	if (NULL == head || NULL == data){
		return NULL;
	}
	node = creatnode(); //创建节点
	if (NULL == node){
		printf("node is null!");
		return NULL;
	}
	node->data = malloc(size); //扩展一个data数据长度的空间
	if (NULL == node->data){ //创建失败则返回
		free(node);
		return NULL;
	}
	memcpy(node->data, data, size); //将数据内存拷贝给节点数据指针
	
	head->pre->next = node;	//最后一个节点为head->pre 
	node->pre = head->pre;
	node->next = head;
	head->pre = node;
	
	return node;
}

link_t *findnode(link_t *head, void *data, int (*cp)(const void *, const void *))
{
	link_t *p = NULL;
	if (NULL == head){
		return NULL;
	}
	p =  head->next; 
	while (p != head){
		if (cp(p->data, data) == 0){
			return p;
		} 
		p = p->next;
	} 
	
	return NULL;
}

link_t* deletenode(link_t *head, void *data, int (*cp)(const void *, const void *))
{
	link_t *p = NULL;
	if (NULL == head){
		return NULL;
	}
	p = findnode(head, data, cp);
	if (NULL == p){
		return p;
	}
	p->pre->next = p->next;
	p->next->pre = p->pre;
	
	free(p->data);
	free(p);
	p = NULL;
	
	return head;
}

link_t* updatenode(link_t *head, void *alter, void *data, int size, int (*cp)(const void *, const void *))
{
	link_t *p = NULL;
	if (NULL == head){
		return NULL;
	}
	p = findnode(head, alter, cp);
	if (NULL == p){
		return p;
	}
	memcpy(p->data, data, size); 
	
	return p;
}

void sort_link(link_t *start, link_t *end, int (*cp)(const void *, const void *))
{
	link_t *l = NULL, *r = NULL;
	void *key = NULL;
	if (NULL == start || NULL == end || start == end || end->next == start || start->pre == end) 
	{
		return;
	}
	l = start, r = end;
	key = l->data;
	while (l != r){
		while(l != r && cp(key, r->data) > 0){ 
			r = r->pre;
		}
		l->data = r->data;
		while(l != r && cp(l->data, key) > 0){
			l = l->next;
		}
		r->data = l->data;
	}
	l->data = key;
	sort_link(start, l->pre, cp);
	sort_link(l->next, end, cp);
}

void display_link(link_t *head)
{
	link_t *p = NULL;
	if (NULL == head){
		return;
	}
	p =  head->next;
	while (p != head){
		printf("%d ", *(int*)p->data);
		p = p->next;
	}
	putchar('\n');
}

void destroy_allnode(link_t *head)
{
	link_t *p = NULL;
	if (NULL == head){
		return;
	} 
	while (head->pre != head){
		p = head->pre;
		head->pre = p->pre;
		free(p->data);
		free(p);
	}
	free(head);
}

int compare(const void* p1, const void *p2)
{
	return *(int*)p1 >= *(int*)p2;
}

通用链表

  • 声明和宏定义:
#ifndef __LIST_HEAD_H__
#define __LIST_HEAD_H__

//通用链表节点类型  双向链表
struct list_head{
    struct list_head *prev; //前级指针
    struct list_head *next;//后级指针
};

void INIT_LIST_HEAD(struct list_head *list);//初始化通用链表
void list_add(struct list_head *node,struct list_head *head);//插入节点
void list_add_tail(struct list_head *node,struct list_head *head);//尾插
void list_del(struct list_head *node);//删除节点

/*遍历链表  依次为:从头节点的下一个节点开始遍历   
*           从头节点的上一个节点开始遍历
*(以list_for_next_each为例理解:首先节点指针pos指向头节点的下一个节点,判断 pos是否指向头节点,不是的话就向后继续遍历)
*/
#define list_for_next_each(pos,head)\for(pos=(head)->next;pos!=(head);pos=pos->next)#define list_for_prev_each(pos,head)\for(pos=(head)->prev;pos!=(head);pos=pos->prev)

//提取数据结构   ptr 是链接因子的指针  type是包含了链接因子的数据类型  member是链接因子成员名
#define container_of(ptr,type,member)\
    (type *)( (int)ptr - (int)(&((type *)0)->member) )

#endif
  • 链表操作函数:
#include "list_head.h"

void INIT_LIST_HEAD(struct list_head *list)//初始化通用链表
{
    //前后级指针都指向本身
    list->next=list;
    list->prev=list;
}
void list_add(struct list_head *node,struct list_head *head)//插入节点
{
    node->next=head->next;
    node->prev=head;
    head->next->prev=node;
    head->next=node;

}
void list_add_tail(struct list_head *node,struct list_head *head)//尾插
{
    node->next=head->prev;
    node->prev=head;
    head->prev->next=node;
    head->prev=node;
}
void list_del(struct list_head *node)//删除节点
{
        node->prev->next=node->next;
        node->next->prev=node->prev;
}

  • 数据定义:
#ifndef __STU_H__
#define __STU_H__
#define N 32
#include "list_head.h"
struct STU{
    int id;
    char name[N];
    char pwd[N];
    float score;
    struct list_head list;//链接因子
};
#endif
  • 测试文件:
#include <stdio.h>
#include <stdlib.h>
#include "list_head.h"
#include "stu.h"

int main(int argc, const char *argv[])
{

    int i;
    struct STU *stu;
    struct STU *stup;
    struct list_head *pos;
    struct list_head stu_list;//学生表的首节点

    stu=(struct STU *)malloc(sizeof(struct STU)*5);  //分配节点空间
    if(!stu)
    {
        perror("fail to malloc");
        return -1;
    }

    //初始化通用链表
    INIT_LIST_HEAD(&stu_list);
    for(i=0;i<5;i++)  //赋值学生信息
    {
        stu[i].id=i;
        sprintf(stu[i].name,"stu%d",i);
        sprintf(stu[i].pwd,"160%d",i);
        stu[i].score=10*i;
        list_add(&stu[i].list,&stu_list);//插入链表
    }

    //遍历学生信息
    list_for_next_each(pos,&stu_list)
    {
        stup=container_of(pos,struct STU,list);
        printf("stu:id=%d,name=%s,pwd=%s,score=%f\n",\
                stup->id,stup->name,stup->pwd,stup->score);
    }

    puts("--------------------------------");

    list_for_prev_each(pos,&stu_list)
    {
        stup=container_of(pos,struct STU,list);
        printf("stu:id=%d,name=%s,pwd=%s,score=%f\n",\
                stup->id,stup->name,stup->pwd,stup->score);
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值