线性表之单链表(C实现)

考察:逻辑思维能力、编程思路清晰度、对内存管理的应用、对指针的灵活运用。

一、链表及其原理

1、存储结构

在线性表 L = ( a 0 , a 1 , . . . , a n − 1 ) 中,将各个元素分布在存储器的不同区域,并将这些区域称为结点。 在线性表 L=(a_0, a_1, ..., a_{n-1}) 中,将各个元素分布在存储器的不同区域,并将这些区域称为结点。 在线性表L=(a0,a1,...,an1)中,将各个元素分布在存储器的不同区域,并将这些区域称为结点。
这些结点之间通过地址或指针来建立联系,以便在需要时能够快速访问和操作这些元素。 这些结点之间通过地址或指针来建立联系,以便在需要时能够快速访问和操作这些元素。 这些结点之间通过地址或指针来建立联系,以便在需要时能够快速访问和操作这些元素。

节点
结点的 d a t a 于存放数据元素 a i ,而 n e x t 域是一个指针,指向 a i 直接后继 a i + 1 所在的结点。 结点的data于存放数据元素a_i,而next域是一个指针,指向a_i直接后继a_{i+1}所在的结点。 结点的data于存放数据元素ai,而next域是一个指针,指向ai直接后继ai+1所在的结点。
在这里插入图片描述

2、结点类型描述

typedef struct node
{
	data_t data;//终节点的数据域
	struct node *next;//终节点的后继指针域
}listnode, *linklist;

设 P 指向链表中的结点 a i 。 设P指向链表中的结点a_i。 P指向链表中的结点ai
获取 a i ,写作: p − > d a t a ; 获取a_i,写作:p->data; 获取ai,写作:p>data;
而获取 a i + 1 ,写作: p − > n e x t − > d a t a ; 而获取a_{i+1},写作:p->next->data; 而获取ai+1,写作:p>next>data;
若指针 p 为 N U L L ,则他不指向任何结点,此时获取 p − > d a t a 或 p − > n e x t 是错误的。 若指针p为NULL,则他不指向任何结点,此时获取p->data或p->next是错误的。 若指针pNULL,则他不指向任何结点,此时获取p>datap>next是错误的。
可调用C语言中malloc()函数向系统申请结点的存储空间
linklist p;
p = (linklist)malloc(sizeof(listnode));
则创建一个类型为linklist的结点,且该结点的地址已存入指针变量p中;

二、单链表创建

1、建立单链表

依次读入表 L = ( a 0 , . . . . . , a n − 1 ) 中每一元素 a i ( 假设为整型 ) ,若 a i ≠ 结束符( − 1 ), 依次读入表L=(a_0,.....,a_{n-1})中每一元素a_i(假设为整型),若a_i≠结束符(-1), 依次读入表L=(a0,.....,an1)中每一元素ai(假设为整型),若ai=结束符(1),
则为 a i 创建一结点,然后插入表尾,最后返回链表的头结点指针 H 。 则为a_i创建一结点,然后插入表尾,最后返回链表的头结点指针H。 则为ai创建一结点,然后插入表尾,最后返回链表的头结点指针H
链表的结构是在算法运行时动态形成的,也就是说,在算法开始执行之前,链表的结构是不存在的。

linklist list_create()
{
	linklist H;

	H = (linklist)malloc(sizeof(listnode));
	if (NULL == H)
	{
		printf("malloc failed\n");
		return H;
	}

	H->data = 0;
	H->next = NULL;

	return H;
}

三、单链表尾部插入和遍历

1、尾部插入

算法思路:

1、建立一个新结点:①malloc内存 ②赋值。
2、找链表H的尾部节点。
3、做尾部插入。

int list_tail_insert(linklist H, data_t value)	
{
	if (NULL == H)
	{
		printf("H is NULL");
		return -1;
	}
	linklist p;
	linklist q;
	
	//1.new node p
	if ((p = (linklist)malloc(sizeof(listnode))) == NULL)
	{
		printf("malloc failed\n");
		return -1;
	}
	p->data = value;
	p->next = NULL;

	//2.locate tail node
	q = H;
	while (q->next != NULL)
	{
		q = q->next;
	}
	//3.insert
	q->next = p;
	
	return 0;
}

2、链表的遍历

算法思路
1、判断H是否为有效链表。
2、若有效,则打印值p->next->data; 而后p = p->next;

int list_show(linklist H)
{
	linklist p;

	if (NULL == H)
	{
		printf("H is NULL\n");
		return -1;
	}
	
	p = H;
	while (p->next != NULL)
	{
		printf("%d ", p->next->data);
		p = p->next;
	}
	puts("");

	return 0;
}

3、链表的查找

按序号查找:实现list_get(h, i)运算。
算法思路
从链表的a0结点开始,判断当前结点是否为第i个结点。如果是,则返回该结点的指针;如果不是,则继续查找下一个结点,并重复这个过程。依次类推,直到找到第i个结点或遍历完整个链表。

linklist list_get(linklist H, int pos) 
{
	linklist p;
	int i;

	if(NULL == H)
	{
		printf("H is NULL\n");
		return NULL;
	}

	if(pos == -1) 
	{
		return H;
	}

	if(pos < -1)
	{
		printf("pos is invalid\n");
		return NULL;
	}

	p = H;
	i = -1;
	while(i < pos) 
	{
		p = p->next;
		if(p == NULL) 
		{
			printf("pos is invalid\n");
			return NULL;
		}
		i++;
	}

	return p;
}

4、链表的插入

即实现list_insert(h, i, i,)。将x插入表中结点ai之前的情况。
算法思路
①调用算法list_get(h, i-1),获取结点a(i-1)的指针p(ai 之前驱)。
②然后申请一个q结点,存入x,并将其插入p指向的结点之后。
注意:插入时新结点q的next域先指向插入位置后边,然后p指向q。

int list_insert(linklist H, data_t value, int pos)
{
	linklist p;
	linklist q;

	if (NULL == H)
	{
		printf("H is NULL\n");
		return -1;
	}

	//1.locate node p (pos-1)
	p = list_get(H, pos-1);

	if (p == NULL)
	{
		return -1;
	}
	
	//2.new node q
	if ((q = (linklist)malloc(sizeof(listnode))) == NULL)
	{
		printf("malloc failed\n");
		return -1;
	}
	q->data = value;
	q->next = NULL;

	//3.insert
	q->next = p->next;
	p->next = q;

	return 0;
}

5、链表的删除

即实现list_delete(h, i)。
算法思路
采用插入法,首先通过调用函数list_get(h, i-1)来获取结点ai的前驱节点,随后将结点ai从链表中删除。

int list_delete(linklist H, int pos)
{
	linklist p;
	linklist q;
	
	//1
	if(NULL == H)
	{
		printf("H is NULL\n");
		return -1;
	}
	
	//2.locate prior
	p = list_get(H, pos-1);
	if(p == NULL)
	{
		return -1;
	}
	if(p->next == NULL)
	{
		printf("delete pos is invalid\n");
		return -1;
	}

	//3.update
	q = p->next;
	p->next = q->next;//p->next = p->next->next;
	
	//4.free
	printf("free:%d\n",q->data);
	free(q);
	q = NULL;

	return 0;
}

6、链表的释放

即实现list_free(H)。
算法思路
移动头结点H,将p指向H,释放p结点。

linklist list_free(linklist H)
{
	linklist p;

	if(NULL == H)
	{
		return NULL;
	}

	p = H;
	
	printf("free:");
	while(H != NULL)
	{
		p = H;
		H = H->next;
		printf("%d ",p->data);
		free(p);
	}
	puts("");

	return NULL;
}

四、链表的复杂操作

1、链表的反转

设计并实现一个算法,用于将单链表H进行倒置。

算法思路
依次取原链表中各个结点,将其作为新链表首结点插入H结点后。

int list_reverse(linklist H)
{
	linklist p;
	linklist q;

	if(NULL == H)
	{
		printf("H is NULL\n");
		return -1;
	}

	if(H->next == NULL || H->next->next == NULL)
	{
		return 0;
	}
	
	p = H->next->next;
	H->next->next = NULL;

	while(p != NULL)
	{
		q = p;
		p = p->next;
		q->next = H->next;
		H->next = q;
	}
	
	return 0;
}

2、链表求相邻两结点最大值

假设链表中的每个结点包含一个整型数据域(data),我们需要找出链表中相邻两个结点数据域(data)值之和最大的那个第一结点的指针。
算法思路
在链表中,假设p和q是相邻的两个结点指针。我们需要找到这样一对结点,即p指向的结点和q指向的结点的数据之和是最大的。最后,返回指向p的指针即可。

linklist list_adjmax(linklist H, data_t *value)
{
	linklist p, q, r;
	data_t sum;

	if(NULL == H)
	{
		printf("H is NULL\n");
		return NULL;
	}

	if(H->next == NULL || H->next->next == NULL || \
       H->next->next->next == NULL)
	{
		return H;
	}

	q = H->next;
	p = H->next->next;
	r = q;
	sum = q->data + p->data;

	while(p->next != NULL)
	{
		p = p->next;
		q = q->next;
		if(sum < q->data + p->data)
		{
			sum = q->data + p->data;
			r = q;
		}
	}
	*value = sum;
	return r;
}

3、有序链表合并

设两单链表A、B按data值(设为整型)递增有序,将表A和B合并成一表A,且表A也按data值递增有序。
算法思路
设指针p、q分别指向表A和B中的结点,若p->data ≤q->data则p结点进入结果表,否则q结点进入结果表。

int list_merge(linklist H1, linklist H2)
{
	linklist p, q, r;

	if(NULL == H1 || NULL == H2)
	{
		printf(" H1 or H2 is NULL\n");
		return -1;
	}
	
	p = H1->next;
	q = H2->next;
	r = H1;
	H1->next = NULL;
	H2->next = NULL;
	
	while(p && q)//while(p != NULL && q != NULL)
	{
		if(p->data <= q->data)
		{
			r->next = p;
			p = p->next;
			r = r->next;
			r->next = NULL;
		}
		else
		{
			r->next = q;
			q = q->next;
			r = r->next;
			r->next = NULL;
		}
	}
	if(p == NULL)
	{
		r->next = q;
	}
	else
	{
		r->next = p;
	}
	return 0;
}

五、程序

1、test.c

#include <stdio.h>
#include "linklist.h"

void test_get();
void test_insert();
void test_delete();
void test_reverse();
void test_adjmax();

int main(int argc, char *argv[])
{
	linklist H1, H2;
	int arr1[] = {1, 3, 5, 7, 9, 14, 17, 19};
	int arr2[] = {2, 4, 6, 8, 10, 13, 15, 20};
	int i;

	H1 = list_create();
	if(NULL == H1)
		return -1;
	
	H2 = list_create();
	if(NULL == H2)
		return -1;
	
	for(i = 0; i < sizeof(arr1)/sizeof(int); i++)
	{
		list_tail_insert(H1, arr1[i]);
	}

	for(i = 0; i < sizeof(arr2)/sizeof(int); i++)
	{
		list_tail_insert(H2, arr2[i]);
	}

	list_show(H1);
	list_show(H2);

	list_merge(H1, H2);
	printf("merge:\n");

	list_free(H1);
	list_free(H2);

	return 0;
}


void test_get()
{

	linklist H;
	int value;
	linklist p;

	H = list_create();

	if(NULL == H)
		return;
	
	printf("input:");
	while(1)
	{
		scanf("%d",&value);
		if(value == -1)
		{
			break;
		}
		list_tail_insert(H, value);
		printf("input:");
	}

	list_show(H);

	p = list_get(H, 4);
	if(p != NULL)
	{
		printf("value=%d\n",p->data);
	}
}


void test_insert()
{
	linklist H;
	int value;

	H = list_create();

	if(NULL == H)
		return;
	
	printf("input:");
	while(1)
	{
		scanf("%d",&value);
		if(value == -1)
		{
			break;
		}
		list_tail_insert(H, value);
		printf("input:");
	}

	list_show(H);

	list_insert(H, 100, 2);

	list_show(H);
}


void test_delete()
{
	linklist H;
	int value;

	H = list_create();

	if(NULL == H)
		return;
	
	printf("input:");
	while(1)
	{
		scanf("%d",&value);
		if(value == -1)
		{
			break;
		}
		list_tail_insert(H, value);
		printf("input:");
	}

	list_show(H);
	printf("H = %p\n", H);
	H = list_free(H);
	printf("H = %p\n", H);

	list_delete(H, -4);

	list_show(H);
}

void test_reverse()
{
	
	linklist H;
	int value;

	H = list_create();

	if(NULL == H)
		return;
	
	printf("input:");
	while(1)
	{
		scanf("%d",&value);
		if(value == -1)
		{
			break;
		}
		list_tail_insert(H, value);
		printf("input:");
	}

	list_show(H);
	list_reverse(H);
	list_show(H);

	list_free(H);
}

void test_adjmax()
{	
	linklist H;
	linklist r;
	int value;
	int sum;

	H = list_create();

	if(NULL == H)
		return;
	
	printf("input:");
	while(1)
	{
		scanf("%d",&value);
		if(value == -1)
		{
			break;
		}
		list_tail_insert(H, value);
		printf("input:");
	}

	list_show(H);
	r = list_adjmax(H, &sum);
	if(r != NULL && r != H)
	{
		printf("data:%d, sum:%d\n", r->data, sum);
	}
	list_show(H);

	list_free(H);
}

2、linklist.c

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


linklist list_create()
{
	linklist H;

	H = (linklist)malloc(sizeof(listnode));
	if (NULL == H)
	{
		printf("malloc failed\n");
		return H;
	}

	H->data = 0;
	H->next = NULL;

	return H;
}

int list_tail_insert(linklist H, data_t value)	
{
	if (NULL == H)
	{
		printf("H is NULL");
		return -1;
	}
	linklist p;
	linklist q;
	
	//1.new node p
	if ((p = (linklist)malloc(sizeof(listnode))) == NULL)
	{
		printf("malloc failed\n");
		return -1;
	}
	p->data = value;
	p->next = NULL;

	//2.locate tail node
	q = H;
	while (q->next != NULL)
	{
		q = q->next;
	}
	//3.insert
	q->next = p;
	
	return 0;
}

int list_show(linklist H)
{
	linklist p;

	if (NULL == H)
	{
		printf("H is NULL\n");
		return -1;
	}
	
	p = H;
	while (p->next != NULL)
	{
		printf("%d ", p->next->data);
		p = p->next;
	}
	puts("");

	return 0;
}

linklist list_get(linklist H, int pos) 
{
	linklist p;
	int i;

	if(NULL == H)
	{
		printf("H is NULL\n");
		return NULL;
	}

	if(pos == -1) 
	{
		return H;
	}

	if(pos < -1)
	{
		printf("pos is invalid\n");
		return NULL;
	}

	p = H;
	i = -1;
	while(i < pos) 
	{
		p = p->next;
		if(p == NULL) 
		{
			printf("pos is invalid\n");
			return NULL;
		}
		i++;
	}

	return p;
}

int list_insert(linklist H, data_t value, int pos)
{
	linklist p;
	linklist q;

	if (NULL == H)
	{
		printf("H is NULL\n");
		return -1;
	}

	//1.locate node p (pos-1)
	p = list_get(H, pos-1);

	if (p == NULL)
	{
		return -1;
	}
	
	//2.new node q
	if ((q = (linklist)malloc(sizeof(listnode))) == NULL)
	{
		printf("malloc failed\n");
		return -1;
	}
	q->data = value;
	q->next = NULL;

	//3.insert
	q->next = p->next;
	p->next = q;

	return 0;
}
int list_delete(linklist H, int pos)
{
	linklist p;
	linklist q;
	
	//1
	if(NULL == H)
	{
		printf("H is NULL\n");
		return -1;
	}
	
	//2.locate prior
	p = list_get(H, pos-1);
	if(p == NULL)
	{
		return -1;
	}
	if(p->next == NULL)
	{
		printf("delete pos is invalid\n");
		return -1;
	}

	//3.update
	q = p->next;
	p->next = q->next;//p->next = p->next->next;
	
	//4.free
	printf("free:%d\n",q->data);
	free(q);
	q = NULL;

	return 0;
}

linklist list_free(linklist H)
{
	linklist p;

	if(NULL == H)
	{
		return NULL;
	}

	p = H;
	
	printf("free:");
	while(H != NULL)
	{
		p = H;
		H = H->next;
		printf("%d ",p->data);
		free(p);
	}
	puts("");

	return NULL;
}

int list_reverse(linklist H)
{
	linklist p;
	linklist q;

	if(NULL == H)
	{
		printf("H is NULL\n");
		return -1;
	}

	if(H->next == NULL || H->next->next == NULL)
	{
		return 0;
	}
	
	p = H->next->next;
	H->next->next = NULL;

	while(p != NULL)
	{
		q = p;
		p = p->next;
		q->next = H->next;
		H->next = q;
	
	}

	return 0;
}

linklist list_adjmax(linklist H, data_t *value)
{
	linklist p, q, r;
	data_t sum;

	if(NULL == H)
	{
		printf("H is NULL\n");
		return NULL;
	}

	if(H->next == NULL || H->next->next == NULL || \
       H->next->next->next == NULL)
	{
		return H;
	}

	q = H->next;
	p = H->next->next;
	r = q;
	sum = q->data + p->data;

	while(p->next != NULL)
	{
		p = p->next;
		q = q->next;
		if(sum < q->data + p->data)
		{
			sum = q->data + p->data;
			r = q;
		}
	}
	*value = sum;
	return r;
}

int list_merge(linklist H1, linklist H2)
{
	linklist p, q, r;

	if(NULL == H1 || NULL == H2)
	{
		printf(" H1 or H2 is NULL\n");
		return -1;
	}
	
	p = H1->next;
	q = H2->next;
	r = H1;
	H1->next = NULL;
	H2->next = NULL;
	
	while(p && q)//while(p != NULL && q != NULL)
	{
		if(p->data <= q->data)
		{
			r->next = p;
			p = p->next;
			r = r->next;
			r->next = NULL;
		}
		else
		{
			r->next = q;
			q = q->next;
			r = r->next;
			r->next = NULL;
		}
	}
	if(p == NULL)
	{
		r->next = q;
	}
	else
	{
		r->next = p;
	}
	return 0;
}

3、linklist.h

typedef int data_t;
typedef struct node

{
	data_t data;
	struct node *next;
}listnode, *linklist;

linklist list_create();
int list_tail_insert(linklist H, data_t value);//head
linklist list_get(linklist H, int pos);
int list_insert(linklist H, data_t value, int pos);
int list_show(linklist H);
int list_delete(linklist H, int pos);
linklist list_free(linklist H);
int list_reverse(linklist H);
linklist list_adjmax(linklist H, data_t *value);
int list_merge(linklist H1, linklist H2);
  • 12
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值