数据结构学习---线性表的链表存储

线性表的链表存储,今天主要对其中重要的操作进行分析,其他的操作均可由基本操作拓展得到。
学数据结构必须得吃透每一个句子,只有真正理解了,数据结构才能了然于心。
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
typedef int ElemType;                 //用户自定义类型
typedef struct LNode
{
	ElemType num;                 
	struct LNode *next;

}LNode,*LinkList;    
int InitLinkList(LinkList &T)                   /  
{
	T=(LinkList)malloc(sizeof(LNode));
	if(!T) return ERROR;
	T->next=NULL;
	return OK;
}
int InsertElement(LinkList T,ElemType elem)       
{
	LinkList temp;
	temp=(LinkList)malloc(sizeof(LNode));
	if(!temp) return ERROR;
	temp->num=elem;
	while(T->next)
	    T=T->next;
	temp->next=T->next;
	T->next=temp;
	return OK;
}
int DeleteElement(LinkList T,ElemType elem)
{
	LinkList pre;
	while(T->next)
	{
		pre=T;
		T=T->next;
		if(T->num==elem)
		{
			pre->next=T->next;
			free(T);
			return OK;
		}
	}
	printf("删除数据不存在\n");;
	return ERROR;
}
int ListLength(LinkList T)
{
	int j=0;
	while(T->next)
	{
		T=T->next;
		j++;
	}
	return j;
}
void visitLinkList(LinkList T)
{
	LinkList h=T;
	h=h->next;
	while(h)
	{
		printf("%d\t",h->num);
		h=h->next;
	}
}
int main()
{
	int i;
	LinkList a;
	i=InitLinkList(a);
	for(i=1;i<=50;i++)
		InsertElement(a,i);
	i=ListLength(a);
	printf("线性链表的长度为%d\n",i);
	visitLinkList(a);
}

注意:

一.typedef struct 和struct区别

typedef struct LNode
{
	ElemType num;
	struct LNode *next;

}LNode,*LinkList;  
1.typedef的作用是什么?简单地讲,为现有类型创建一个新的名字,或称为类型别名。

typedef struct 
{
	ElemType num;
	struct LNode *next;      //编译器会报错

}LNode,*LinkList;  
那么这个与前一个又有什么区别呢?显然,这个struct并没有名字,因此当定义struct LNode *next时,编译器根本不晓得存在一个结构体叫LNode。尽管我们用typedef为struct创建一个新名字LNode.

我们现在来看一看实际上第一段代码是分为两个部分的。

第一部分:

struct LNode
{
	ElemType num;
	struct LNode *next;

};  
第二部分

typedef struct LNode LNode,*LinkList 
也就是说先对结构体定义,然后再起别名。


二.LNode和LinkList区别

    结构体类型LNode是单链表中的结点类型,它包括两个成员项,其一是数据域elem,用于存放某个数据元素本身的信息,其类型为通用类型标示符ElemType,由用户在使用时自行定义;其二是指针域next,用于存放某结点的直接后继结点的存储地址,即它指向某结点的直接后继结点,显然类型为struct LNode *类型。

    LinkList是指向LNode结构体类型的指针类型,实际上就是和LNode*类型一样,只不过名字不一样而已。

两者的大小区别:

(1)LNode因为是结构体大小,所以所占内存大小由结构体内的变量大小所决定。

(2)LinkList是指针,而指针的内存空间无论指向什么类型的变量,都只跟cpu寻址字长有关,而在我的系统中长度为4.


三.指针和指针引用

int InitLinkList(LinkList &T)                   /  
{
	T=(LinkList)malloc(sizeof(LNode));
	if(!T) return ERROR;
	T->next=NULL;
	return OK;
}
一开始我很奇怪,为什么需要对LinkList加上引用.

指针其实类似于int、char等类型,只不过其存放的是地址,而不是一个具体的元素信息。

由此,当我没加上&的时候

int InitLinkList(LinkList T)                   /  
{
	T=(LinkList)malloc(sizeof(LNode));
	if(!T) return ERROR;
	T->next=NULL;
	return OK;
}
这个函数为T申请一个头结点,其分配的空间会在函数结束后消失,并不能改变实参。

而当加上&后,在函数里申请到的头结点会影响到实参,从而达到了修改实参的效果。


四.为什么在其他函数里却不用加&

int InsertElement(LinkList T,ElemType elem)       
{
	LinkList temp;
	temp=(LinkList)malloc(sizeof(LNode));
	if(!temp) return ERROR;
	temp->num=elem;
	while(T->next)
	    T=T->next;
	temp->next=T->next;
	T->next=temp;
	return OK;
}
(1)我在这里没有加&的原因很简单,实际上我并不需要对T所指向的内容进行修改。而我需要修改的是T->next的内容

由于next是struct LNode*类型,所以我在函数里可以直接对next所指向的内容直接进行修改。


(2)是否有必要每次都要重新定义一个LinkList p指向头结点

int InsertElement(LinkList &T,ElemType elem)       
{
	LinkList p=T,temp;
        
        temp=(LinkList)malloc(sizeof(LNode));
	if(!temp) return ERROR;
	temp->num=elem;
	while(p->next)
	    p=p->next;
	temp->next=p->next;
	p->next=temp;
	return OK;
}
我在上面已经讲过,如果在
int InsertElement(LinkList &T,ElemType elem)   里对LinkList加上引用后,会对实参T进行修改
所以当你用T=T->next时,T所指向的内容一直在改变,而我们其实并不需要它改变,由此我们将T的所指向的内容赋给p,p进行p=p->next,
当函数结束时p所指向的内容会消失,而不会对实参造成任何影响。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值