【数据结构三】链表之单链表易错点,概念分析和代码分享——链表在函数内部的引用,链表的表头指针和表头结点,其他类型的链表

说明:

以下代码均用c++编写,
linux下可以编译和执行:

g++ LinkList_use.cpp -o LinkList_use
./LinkList_use

易错点:

1.链表的表头指针和表头结点

平时我们看到的定义是这样的:

typedef struct LNode{
	int data;
	struct LNode *next;
}LNode, *LinkList;

这里的LinkList加了*后,总是让人很迷惑,
再加上一些什么头结点,整个人都晕晕的了……
在这里插入图片描述
实际上,所有的LinkList都指文中的红色部分,它只是一个指针,占用内存为8字节!
头结点是绿色区域,不仅需要头指针,还需要一个额外的空结点,它的data是空,指针指向第一个数值。

2.链表在函数内部的引用:

可能你说上面太简单了,那么,看下面的函数:
这里的LinkList L应该是LinkList &L还是LinkList *L还是LinkList L呢?

/**
 * 递归算法
 * 删除不带头结点的单链表里的所有值为x的结点
 *
 * 终止条件:子链表为空
 * 递归主体:如果发现了值为x的结点,删除L结点,
 *           否则继续去子链里找
 *
 */
void DeleteAllX(LinkList ?L,int x){
	if(L!=NULL)
		if(x!=L->data)
			DeleteAllX(L->next,x);
		else
		{
			LNode *p=L;
			L = L->next;
			free(p);
			DeleteAllX(L,x);
		}
	else	
		return;
}

正确答案是LinkList &L
首先,调用函数的时候:

		LinkList l1;
        l1=List_HeadInsert(l1);//创建结点
        PrintList(l1);
        DeleteAllX(l1,2); //递归删除结点中为data==2的结点
        PrintList(l1);

LinkList L传入了一个头指针,它存储了指针,得到的结果会是一堆奇怪的值,因为虽然指针被传递过去了,但只是一个copy的值,一旦函数结束,
在这里插入图片描述
LinkList *L肯定不行,编译会直接报错,因为传参是DeleteAllX(l1,2);除非是DeleteAllX(&l1,2);这样子传过去,但要使用L->data也是会报错的

应该是LinkList &L,这样获得的就是指针本身,对L进行各种修改也是会被更新的
可以看到如果没有使用&LL = L->next;永远也不能生效~!!
在这里插入图片描述

3.其他类型的链表~
/****
 *
 * 双链表
 *
 */
typedef struct DNode{
	int data;
	struct DNode *prior,*next;
}DNode, *DLinkList;

/**
 * 静态链表
 * 表头 SLinkList[index] 其中表头为index=0 ;
 * 表尾 next = -1;
 */
# define MaxSize 50
typedef struct{
	int data;
	int next;
}SLinkList[MaxSize];

代码:

LinkList.h:

typedef struct LNode{
	int data;
	struct LNode *next;
}LNode, *LinkList;

/***
 * 利用头插法建立单链表
 */
LinkList List_HeadInsert(LinkList &L){
	std::cout<<"开始用头插法创建链表,输入-1结束"<<std::endl;
	LNode *s;
	int x;
	L = (LinkList)malloc(sizeof(LNode));
	L->next = NULL;
	scanf("%d",&x);
	while(x != -1){
		s = (LNode*)malloc(sizeof(LNode)); //创建结点
		s->data = x;
		s->next = L-> next;
		L->next = s;
		scanf("%d",&x);
	}
	return L;
}


/***
 * 利用尾插法建立单链表
 */
LinkList List_TailInsert(LinkList &L){
	std::cout<<"开始用尾插法创建链表,输入-1结束"<<std::endl;
        LNode *s;
	LNode *insertP;
        int x;
        L = (LinkList)malloc(sizeof(LNode));
        L->next = NULL;
	insertP = L; //保存最后一个结点的指针
        scanf("%d",&x);
	while(x !=-1){
		s = (LNode*)malloc(sizeof(LNode)); //创建结点
		s->data = x;
		insertP->next = s;
		insertP = s; 
		scanf("%d",&x);
	}
	insertP->next=NULL;
	return L;
}

/**
* 打印链表
*/
void PrintList(LinkList &L){
	LNode *s=L->next;
	while(s!=NULL){
		std::cout<<s->data<<" "<<s<<std::endl;
		s=s->next;
	}
	std::cout<<std::endl;
}

/**
* 按照序号查找结点,返回该结点指针
* 如果超出了结点范围,返回NULL;
*/
LNode* FindIndexNode(LinkList L,int i){
	LNode* p = L;
	int j=0;
	if(i==0)
		return L;
	if(i<0)
		return NULL;
	while(p != NULL && i<j){ //循环的习惯:遇到了可以跳出去的条件,不要犹豫,立刻跳出去!!
		if(i==j)
			return p;
		else{
			p = p->next;
			j++;
		}
	}
	return NULL;
}


/**
 * 按照值进行遍历查找,只返回第一个找到的x结点
 */
LNode* FindNumNode(LinkList L, int x){
	LNode *p = L;
	while(p!=NULL){
		if(x==p->data)
			return p;
		p=p->next;
	}
	return NULL;
}


/****
 *
 * 双链表
 *
 */
typedef struct DNode{
	int data;
	struct DNode *prior,*next;
}DNode, *DLinkList;

/**
 * 静态链表
 * 表头 SLinkList[index] 0 ;
 * 表尾 next = -1;
 */
# define MaxSize 50
typedef struct{
	int data;
	int next;
}SLinkList[MaxSize];


/**
 * 递归算法
 * 删除不带头结点的单链表里的所有值为x的结点
 *
 * 终止条件:子链表为空
 * 递归主体:如果发现了值为x的结点,删除L结点,
 *           否则继续去子链里找
 *
 */
void DeleteAllX(LinkList L,int x){
	//std::cout<<L<<" "<<"  "<<std::endl;
	if(L!=NULL)
		if(x!=L->data)
			DeleteAllX(L->next,x);
		else
		{
			LNode *p=L;
			L = L->next;
			free(p);
			DeleteAllX(L,x);
		}
	else	
		return;
}

LinkList_use:

#include<iostream>
#include"LinkList.h"
#include<malloc.h>

int main(){
        LinkList l1,l2;
        l1=List_HeadInsert(l1);
        PrintList(l1);
        //l2=List_TailInsert(l2);
        //PrintList(l2);
        std::cout<<" "<<l1<<"  "<<&l1<<std::endl;
        DeleteAllX(l1,2);
        std::cout<<" "<<l1<<"  "<<&l1<<std::endl;
        PrintList(l1);
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值