l4-d4 线性表之链表

一、什么是链表及原理

将线性表L=(a0,a1,……,an-1)中各元素分布在存储器的不同存储块,称为结点,通过地址或指针建立元素之间的联系  

 结点的data域存放数据元素ai,而next域是一个指针,指向ai的直接后继ai+1所在的结点。

 带头结点的单链表:

结点类型描述:  

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

若说明:

       listnode A;

       linklist p = &A;

设p指向链表中结点ai

获取ai,写作:p->data;

而取ai+1,写作:p->next->data;

若指针p的值为NULL,则它不指向任何结点, 此时取p->data或p->next是错误的。 

可调用C语言中malloc()函数向系统申请结点的存储空间

          linklist  p;

          p = (linklist)malloc(sizeof(listnode));

则创建一个类型为linklist的结点,且该结点的地址已存入指针变量p中:

二、单链表的实现-创建

1.建立单链表

依次读入表L=(a0,.....,an-1)中每一元素ai(假设为整型),若ai≠结束符(-1),则为ai创建一结点,然后插入表尾,最后返回链表的头结点指针H。

 设L=(2,4,8,-1),则建表过程如下:

链表的结构是动态形成的,即算法运行前,表结构是不存在的。

linklist list_create() {
	linklist H;

	H = (linklist)malloc(sizeof(listnode));
	if (H == NULL) {
		printf("malloc failed\n");
		return H;
	}
	
	H->data = 0;//初始化
	H->next = NULL;

	return H;
}

2.链表查找 

1按序号查找:实现GetLinklist(h, i)运算。

算法思路:从链表的a0起,判断是否为第i结点,若是则返回该结点的指针,否则查找下一结点,依次类推。

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

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

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

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

	return p;
}

2)按值查找(定位) :  即实现Locate(h, x)。

算法思路:从链表结点a0起,依次判断某结点是否等于x,若是,则返回该结点的地址,若不是,则查找下一结点a1,依次类推。若表中不存在x,则返回NULL。

3)链表的插入:即实现InsertLinklist(h, x, i,)。将x插入表中结点ai之前的情况。

算法思路:调用算法GetLinklist(h, i-1),获取结点ai-1的指针p(ai 之前驱),然后申请一个q结点,存入x,并将其插入p指向的结点之后。

3.遍历输出

int list_show(linklist H) {
	linklist p;

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

	p = H;

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

	return 0;
}

三、单链表的实现-尾部插入

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

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

	//1 申请新节点p
	if ((p = (linklist)malloc(sizeof(listnode))) == NULL) {
		printf("malloc failed\n");
		return -1;
	}
	p->data = value;
	p->next = NULL;
	
	//2 定位尾节点 
	q = H;
	while (q->next != NULL) {
		q = q->next;
	}

	//3 插入p
	q->next = p;

	return 0;
}

四、单链表的实现-按位置插入

链表的插入:即实现InsertLinklist(h, x, i,)。将x插入表中结点ai之前的情况。

算法思路:调用算法GetLinklist(h, i-1),获取结点ai-1的指针p(ai 之前驱),然后申请一个q结点,存入x,并将其插入p指向的结点之后。

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

	if (H == NULL) {
		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;
}

五、代码

头文件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);

源程序linklist.c

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

linklist list_create() {
	linklist H;

	H = (linklist)malloc(sizeof(listnode));
	if (H == NULL) {
		printf("malloc failed\n");
		return H;
	}
	
	H->data = 0;
	H->next = NULL;

	return H;
}

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

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

	//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 locate locate locate locate locate locate locate locate tail node 
	q = H;
	while (q->next != NULL) {
		q = q->next;
	}

	//3 insert
	q->next = p;

	return 0;
}

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

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

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

	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 (H == NULL) {
		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_show(linklist H) {
	linklist p;

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

	p = H;

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

	return 0;
}


测试文件test.c

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

void test_get();

int main(int argc, const char *argv[])
{
	linklist H;
	int value;
	
	H = list_create();
	if (H == NULL)
		return -1;

	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, 0);//1 3 5 7
	list_show(H);

	return 0;
}

void test_get() {
	linklist H;
	int value;
	linklist p;
	
	H = list_create();
	if (H == NULL)
		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);//1 3 5 7
	if (p != NULL)
		printf("value=%d\n", p->data);


}

六、作业

1、请简要描述单链表的优缺点。


单链表的优点是插入和删除元素时效率高,因为只需要改变相邻节点的指针即可,不需要移动其他元素。缺点是访问某个元素时效率较低,因为需要从头节点开始遍历整个链表才能找到目标元素。


2、编程实现单链表的创建,链表中的数据由用户输入,允许多次输入,输入-1结束创建新结点。

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

linklist list_ create();
int list_show(linklist H);
int list_tail_insert(Linklist H,data_t value ) ;
#include<stdio. h>
#include "linklist. h"
int main(){
    linklist H;
    int value;
    H=list_create();
    if(H == NULL)
        return -1;
    printf("input:");
    while(1){
        scanf("%d",&value );
        if(value == -1)
            break ;
        list_tail insert(H, value);
        printf("input:");
    }
    list_show(H);
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值