考研二战_数据结构_day3_单链表

目录

一、单链表的定义

二、单链表的基本操作

1、定义

2、初始化

        1、无头结点方式

        2、有头节点方式

        3、小结

3、增

        1、按位序插入

        2、在指定节点后插入(后插)

        3、在指定节点前插入(前插)

4、删

总结


前言

        今天返校,没怎么学。昨晚看了链表的内容,发现我对于指针的使用还是太弱了,需要好好地学习学习。


一、单链表的定义

        每个节点除了存放数据元素外,还要存储指向下一个节点的指针。

        优点:不要求大片连续空间,改变容量方便

        缺点:不可随机存取,要耗费一定空间存放指针


二、单链表的基本操作

1、定义

        用data来存储数据,并且用next来存指向下一个结点的指针。并为了以后使用方便,因此将其重命名,使用LNode时,表示定义的是一个结点;用LinkList的时候表示定义的是一个单链表

typedef struct ListNode{
	ElemType data;
	struct ListNode *next;
}LNode, *LinkList;

2、初始化

        1、无头结点方式

        让单链表L的头指针直接指向NULL

bool InitList(LinkList &L){
	L = NULL;
	return true;
}

        2、有头节点方式

        首先用mallc函数申请一个单链表结点大小的空间,并将单链表L的头指针指向该空间,该空间就是一个头节点。头节点中data部分没有数据;只有一个next指针。随后将该next指针指向NULL,即可完成初始化。

bool InitList(LinkList &L){
	L = (LNode*)malloc(sizeof(LNode));
	if(L == NULL) return false;
	L->next = NULL;
	return true;
}

        3、小结

        使用带头节点的初始化方式,在后续使用时比较方便;不带头节点的方式在后续使用时比较麻烦。

3、增

        1、按位序插入

        由于是从前往后遍历,因此,只需要找到位序为 i-1 的节点,即可非常方便地在位序为 i 的地方插入节点。

//按位序插入,在单链表L位序为i的地方插入结点,其数据元素为elem
bool InsertByOrder(LinkList &L, int i, ElemType elem) {
	if(i<1) return false;  //位序不可小于1

	LNode* p = L;  //指针p指向L的头节点,表示当前扫描的节点
	int j = 0;     //j表示指针p指向节点的位序

	while(p != NULL && j < i-1) { //扫描,找到位序i的前一位
		p = p->next;
		j++;
	}

	if(p == NULL) return false;  //位序i-1为NULL,无法插入

	LNode* temp = (LNode*)malloc(sizeof(LNode));  //定一个节点temp
    if(temp == NULL) return false;  //某些情况下可能创建失败 
	temp->data = elem;
	temp->next = p->next;  //节点temp的指针指向位序为i的节点
	p->next = temp;        //将位序为i-1的节点的next指针指向temp

	return true;
}

        2、在指定节点后插入(后插)

        在仅知晓节点p的情况下,我们只知道p的next指针指向的节点,因此,后插是比较简单的。与按位序插入类似,只需要将temp节点的next指向p的next,再将p的next指向temp即可。

//在指定节点p后插入节点,其数据元素值为elem
bool InsertNextNode(LNode* p, ElemType elem) {
	if(p == NULL) return false;  //节点p本身并不存在

	LNode* temp = (LNode*)malloc(sizeof(LNode));
	if(temp == NULL) return false;  //某些情况下可能创建失败
	temp->data = elem;
	temp->next = p->next;
	p->next = temp;

	return true;
}

        3、在指定节点前插入(前插)

        第一种方法是遍历至p节点,找到其前驱节点,在该节点后插入一个节点,就相当于在节点p前插入一个节点。但是我还没实现查找,而且时间复杂度较高,所以就记了第二种方法。

        在仅知晓节点p的情况下,我们只知道p的next指针指向的节点,那么先在节点p的后面插入一个后继节点temp,随后将p的data赋给temp,那么这个temp节点就成p节点了(看上去是p,用起来也是p,还说你不是p?)随后将elem赋值给初始的那个p节点,这样就前插(夺舍)成功了。

//在指定节点p前插入节点,其数据元素为elem
bool InsertPreNode(LNode* p, ElemType elem) {
	if(p == NULL) return false;  //节点p本身并不存在

	LNode* temp = (LNode*)malloc(sizeof(LNode));
	if(temp == NULL) return false;  //某些情况下可能创建失败

	temp->data = p->data;  //转移数据
	temp->next = p->next;
	p->data = elem;
	p->next = temp;

	return true;
}

4、删

        今天还有事,等明天再复习。


总结

        我对于指针的使用还是不够熟练。我虽然知道链表基本操作的原理,但是如何用代码实现还是比较薄弱,需要多做点题。

测试

int main() {
	LinkList list;
	if(InitList(list)) printf("work!\n");

	LNode* p;  //测试用节点

	for(int i = 0; i<6; i++) {
		ElemType temp = rand() % 10 + 1;  //生成一个1~10的数
		if(InsertByOrder(list, i+1, temp)) {
			printf("数字%d插入成功!\n", temp);
		} else {
			printf("插入失败!\n");
		}
	}

	p = list->next;  //p指向第一个元素
	while(p) {
		printf("%d ", p->data);
		p = p->next;
	}
	puts(""); 

	p = list->next->next;  //p指向第二个元素
	if(InsertNextNode(p, 3)) {  //后插元素3
		printf("数字插入成功!\n");
	} else {
		printf("插入失败!\n");
	}
	if(InsertPreNode(p, 7)) {  //前插元素7
		printf("数字插入成功!\n");
	} else {
		printf("插入失败!\n");
	}

	p = list->next;  //遍历
	while(p) {
		printf("%d ", p->data);
		p = p->next;
	}

	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值