单向链表的基本操作

这篇文章也是为了复习下,同时为字典树做下准备

链表操作包括创建,删除,增加,排序,输出等操作,后续将代码贴上

单向链表:      head ---->[NULL] 

空链表:head---->[p1]---->[p2]...---->[pn]---->[NULL]

             p1->next  p2->next   pn->next

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

int n = 0; //节点个数

typedef struct db
{
	int num;
	int score;
	struct db *next;//这个是创建链表的关键
};

#define LEN sizeof(struct db)

//返回值是链表表头
struct db *list_create()
{
	struct db *head = NULL;//头节点
	struct db *p1 = NULL; //p1保存创建的新节点的地址
	struct db *p2 = NULL;

	n = 0;//当前链表节点
	p1 = (struct db*) malloc(LEN);

	//重要的一步,要把p1保存下来
	p2 = p1;
	//还要判断有没有申请内存成功
	if (NULL == p1)
	{
		return NULL;
	}
	else
	{
		printf("plz input num in node %d\n", n + 1);
		scanf("%d %d", &p1->num, &p1->score);
	}
	while (0 != p1->num)
	{
		n += 1;
		if (1 == n) //第一个节点
		{
			head = p1;
			p2->next = NULL; //记住,相当于下一个节点是NULL,之前p1已经赋给了p2
		}
		else
		{
			p2->next = p1;//下一个节点
		}
		p2 = p1; //p1将要生成新的地址
		p1 = (struct db*) malloc(LEN);
		//还要判断有没有申请内存成功
		if (NULL == p1)
		{
			return NULL;
		}
		printf("plz input num in node %d\n", n + 1);
		scanf("%d %d", &p1->num, &p1->score);

	}
	//单向链表的结尾就是指向NULL
	p2->next = NULL;
	free(p1);
	p1 = NULL;

	return head;
}

void list_print(struct db *node)
{
	struct db *p1 = NULL;
	if (NULL == node)
	{
		return;
	}
	p1 = node->next;
	printf("%d %d\n", node->num, node->score);
	while (NULL != p1)
	{
		printf("%d %d\n", p1->num, p1->score);
		p1 = p1->next;
	}
	return;
}

int list_search(struct db* node, int num)
{
	int count = 0;
	struct db *p1 = NULL;
	if (NULL == node)
	{
		return 0;
	}
	if (num == node->num) count += 1;
	p1 = node->next;
	//printf("%d %d\n",node->num,node->score);
	while (NULL != p1)
	{
		if (num == node->num) count += 1;
		p1 = p1->next;
	}
	return count;
}

struct db* list_inser(struct db *pdb, int index, int num, int score)
{
	struct db *p1 = NULL;
	struct db *p2 = NULL;
	struct db *p3 = NULL;
	int count     = 1;

	p1 = pdb;

	if ((NULL == pdb) && (0 != index))
	{
		printf("pdb is NULL, and index is not 0, it's %d\n", index);
		return NULL;
	}

	if ((NULL == pdb) && (0 == index))
	{		
		//空链表,然后要加入的是头节点
		p2 = (struct db*) malloc(LEN);
		if (NULL == p2)
		{
			printf("malloc error\n");
			return NULL;
		}
		p2->num   = num;
		p2->score = score;
		p2->next = NULL;
		pdb = p2;
		n += 1;
		return pdb;
	}

	while ((NULL != p1) && (count != index))
	{
		p1 = p1->next;
		count += 1;
	}

	p2 = (struct db*) malloc(LEN);
	if (NULL == p2)
	{
		printf("malloc error\n");
		return NULL;
	}
	p2->num   = num;
	p2->score = score;

	p3 = p1->next;
	p1->next = p2;
	p2->next = p3;
	n += 1;
	return pdb;
}

struct db* list_remove(struct db *pdb, int index)
{
	struct db *p1 = NULL;
	struct db *p2 = NULL;
	struct db *p3 = NULL;
	int    count     = 1;
	if (NULL == pdb) 
	{
		printf("pdb is NULL\n");
		return NULL;
	}

	p1 = pdb;

	//一开始没有考虑要删头节点的情况,这个要单独考虑的,否则会core
	if(1 == index)
	{
		pdb = pdb->next;
		free(p1);
		p1 = NULL;
		return pdb;
	}
	while((NULL != p1) && (count != index))
	{
		p2 = p1; //保存当前节点,如果下一个节点就是的话,这个会用上
		p1 = p1->next;
		count+=1;
	}

	p2->next = p1->next;
	free(p1);
	p1 = NULL;
	n-=1;

	
	return pdb;
}

struct db* list_convert(struct db* pdb)
{
	struct db* p1;  
	struct db* p2;  //临时存储
	struct db* p3;  //最后输出的列表

	p1 = pdb; //存储的初始的列表
	//除head外的第一个节点的next要变成NULL
	p3 = NULL; 
	while(NULL != p1)
	{
		p2 = p1->next;
		p1->next = p3;
		p3 = p1; //存储中间节点的
		p1 = p2;

	}

	return p3;
}

//按照score排序
struct db*  list_sort(struct db* pdb)
{
	struct db* first; //有序链表的头指针
	struct db* tail; //有序链表的尾指针
	struct db* min;  //最小值的节点
	struct db* pre_min;//保存当前最小值节点的前驱节点,保存这个是为了后面重新调整链表用的
	struct db* p;
	if(NULL == pdb) return NULL;
	while(NULL != pdb)
	{
		for(p = head,min=head;p->next!=NULL;p=p->next) //为什么是p->next != NULL不是p!=NULL,后来想了下确实不需要p!=NULL,因为一开始head已经判断过,后面next也是个节点
		{
			if(min->score > p->score)
			{
				//将值小的点放入新的链表
				if(NULL == first)
				{
					first = p;
					tail = NULL;
				}
				else
				{
					
				}

			}
		}
	}
	
}

//写链表这类程序,关键是理解:head存储的是第一个节点的地址,
//head->next存储的是第二个节点的地址;任意一个节点p的地址,只能通过它前一个节点的next来求得
int main()
{
	struct db *head = NULL;
	int index = 0;
	int insertnum = 0;
	int inserscore = 0;
	freopen("input.txt", "r", stdin);
	//链表的创建
	head = list_create();

	int num = 20;
	//链表查找
	list_search(head, num);

	//链表删除
	/*1、 head就是第1个节点,head->next就是第2个节点;
	2、删除后head指向第2个节点,就是让head=head->next。
	---->[1]---->[2]---->[3]...---->[n]---->[NULL](原链表)
	head   1->next  2->next  3->next   n->next

	---->[1]---->[3]...---->[n]---->[NULL](删除后链表)
	head   1->next  3->next   n->next*/
	//scanf("%d", &index);
	//head = list_remove(head, index);
	
	list_print(head);

	//链表反序
	//原来的head头要跑到最后,原来的p1->next = p2变成p2->next=p1
	//反序还是不理解,要背诵
	head = list_convert(head);
	//链表输出
	list_print(head);

	

	//链表增加
	//指定节点插入
	scanf("%d %d %d", &index, &insertnum, &inserscore);
	head = list_inser(head, index, insertnum, inserscore);

	//链表排序
	head = list_sort(head);



	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值