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

来源:互联网 发布:geo数据库简介 编辑:程序博客网 时间:2024/06/03 21:17
线性表的链表存储,今天主要对其中重要的操作进行分析,其他的操作均可由基本操作拓展得到。学数据结构必须得吃透每一个句子,只有真正理解了,数据结构才能了然于心。#include<stdio.h>#include<stdlib.h>#define OK 1#define ERROR 0typedef 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