您的位置:首页 > 理论基础 > 数据结构算法

线性表的链式表示和实现

2017-09-21 08:37 309 查看

线性表的链式表示和实现

首先来看一下线性表的顺序存储和链式存储的区别

顺序存储结构 —— 可随机存储,但插入或删除需要移动大量元素

链式存储结构 —— 便于插入或删除,但不可随机存取(其实可以通过操作使其随机存取)

线性链表

以存储的数据为整型(int)为例:

头结点的定义:

typedef struct HNode{
int length;
char info[100];
struct LNode *next;
}HNode;


注:大部分示例程序都直接用链表节点的类型来声明头节点,但我觉得应该为头节点定义单独的类型,也许这样会使操作变得略微麻烦,但也会带来很多好处。比如,当链表中的节点存储的数据为浮点型数组、字符型数组等类型的数据,而头结点是用整形来存储链表的长度的时候,分开定义更为合理。

链表节点的定义

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


1、创建空链表

HNode* createNullList()         /**创建空链表的函数的定义**/
{
HNode* head;
head=(HNode*)malloc(sizeof(HNode));
head->length = 0;
if(head!=NULL){
head->next=NULL;
printf("Has create null list success!\n");
}
else
printf("Out of space!\n");
return head;
}


2、判断链表是否为空

int isNullList(HNode *head)      /**判断是否链表是否为空的函数的定义(Y-1,N-0)**/
{
return head->next==NULL;
}


3、在链表的结尾添加新节点

int append_t(HNode *head, int n)      /**在已存在的链表最后增加一个新结点的函数的定义(Y-1,N-0)**/
{
LNode *p, *pnew;
pnew=(LNode*)malloc(sizeof(LNode));
if(pnew==NULL){
printf("Out of space!\n");
return 0;
}
else{
pnew->data = n;
p = head->next;                 /*p先指向头结点*/
if(p == NULL){                  /*如果链表为空*/
head->next = pnew;
pnew->next = NULL;
}
else{
while(p->next!=NULL)        /*若p所指不是链尾*/
p=p->next;              /*p后移一个结点*/
p->next=pnew;               /*链尾的next存储新结点指针*/
pnew->next=NULL;            /*使新结点成为链尾*/
}
head->length++;
}
return 1;
}


4、由结点中的元素查找结点的位序

int locate(HNode *head, int n, LNode **p)  /**求某结点的指针,并返回其位序的函数的定义**/
{
int i = 1;
*p = NULL;
*p = head->next;                   /*将头结点的next域赋值给p,使指向第一个结点*/
while(*p != NULL && (*p)->data != n){
i++;
*p = (*p)->next;
}
if(*p == NULL)
return 0;
return i;
}


5、由某结点的指针查找该节点的前驱结点的指针

LNode* locatePre(HNode *head, LNode *p)   /**求p所指结点的前驱的函数的调用**/
{
LNode *ptemp;
ptemp = head->next;
while(ptemp != NULL && ptemp->next != p)
ptemp = ptemp->next;
return ptemp;
}


6、在某结点之后插入一个新结点

int append_t(HNode *head, int n)      /**在已存在的链表最后增加一个新结点的函数的定义(Y-1,N-0)**/
{
LNode *p, *pnew;
pnew=(LNode*)malloc(sizeof(LNode));
if(pnew==NULL){
printf("Out of space!\n");
return 0;
}
else{
pnew->data = n;
p = head->next;                 /*p先指向头结点*/
if(p == NULL){                  /*如果链表为空*/
head->next = pnew;
pnew->next = NULL;
}
else{
while(p->next!=NULL)        /*若p所指不是链尾*/
p=p->next;              /*p后移一个结点*/
p->next=pnew;               /*链尾的next存储新结点指针*/
pnew->next=NULL;            /*使新结点成为链尾*/
}
head->length++;
}
return 1;
}


7、删除结点

int deletendnd(HNode *head, int i, int *e)           /**结点的删除函数的定义**/
{
int j = 0;
LNode *p, *q;
p = head->next;
if(i == 1){
j = 1;
head->next = p->next;
*e = p->data;
free(p);
return 1;
}
while(p->next != NULL && j < i-2){
p = p->next;
j++;
}
if(!(p->next) || j > i-2)
return 0;
q = p->next;
p->next = q->next;
*e = q->data;
free(q);
head->length--;
return 1;
}


————————————————————————————-

完整代码:

除了以上基本操作外,本代码又添加了一些其他功能,并且改善了交互性。

本代码的头结点与其余结点采用的是不同的数据类型,因此增加了代码的复杂性

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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

typedef struct HNode{ int length; char info[100]; struct LNode *next; }HNode;

HNode* createNullList(); /**创建空链表的函数的声明**/
int isNullList(HNode*); /**判断是否链表是否为空的函数的声明(Y-1,N-0)**/
int append_h(HNode*, int); /**在已存在的链表最前增加一个新结点的函数的声明(Y-1,N-0)**/
int append_t(HNode*, int); /**在已存在的链表最后增加一个新结点的函数的声明(Y-1,N-0)**/
int locate(HNode*, int, LNode**); /**求某结点的指针并返回位序的函数的声明**/
LNode* locatePre(HNode*, LNode*); /**求p所指结点的前驱的函数的声明**/
LNode* locfda(HNode*, int); /**查找某位序的元素的数据的函数的声明**/
int insert(HNode*, LNode*, int); /**在某结点之后插入一个新结点的函数的声明(Y-1,N-0)**/
int deletendndnd(HNode*, int); /**结点的删除函数的声明**/
int clear(HNode*); /**清空链表的函数的声明**/
int batchadd(HNode*, int, int*); /**批量添加结点的函数的声明**/
void reverse(HNode*); /**单链表的就地逆置函数的声明**/
void print_L(HNode*);
void print_hyphen(int);

/******************************************************************************************************************/

int main(void)
{
int data; /*结构体成员的数据*/
LNode *p;

print_hyphen(5);
printf("单链表的操作示例");
print_hyphen(5);
printf("\n");

HNode *head;
if((head=createNullList()) != NULL) /**创建空链表的函数的调用**/
{
char info[50];
printf("请输入此链表的信息(50个字符以内):\n");
gets(info);
strcpy(head->info, "The example for CSDN!\n");
strcpy(head->info + strlen("The example for CSDN!\n"), info);
}
else{
exit(1);
}

int end = 0;
while(!end){
print_hyphen(15); printf("\n");
printf("请输入指令来执行操作\n");
print_hyphen(15); printf("\n");
printf("1、判断链表是否为空\n2、在链表最前增加一个新结点\n3、在链表最后增加一个新结点\n4、查找某位序的元素的数据\n");
printf("5、在某结点之后插入一个新结点\n6、删除某结点并返回其值\n7、查找某元素的位序\n8、清空链表\n");
printf("9、求某结点的前驱\n10、查看链表信息\n11、批量添加结点\n12、显示链表长度\n13、查看链表数据\n14、逆置链表\n15、退出演示\n");
print_hyphen(15); printf("\n");
printf("输入要使用的功能的序号: ");
int opt;
scanf("%d",&opt);
print_hyphen(15);
printf("\n");
switch(opt){
case 1:
if(isNullList(head)) /**判断是否链表是否为空的函数的调用(Y-1,N-0)**/
printf("链表为空!\n");
else
printf("链表不为空!\n");
break;

case 2:
printf("请输入要添加到链头的结点的数据: ");
scanf("%d",&data); /**输入要添加的结点的数据*/
if(append_h(head, data)) /**在已存在的链表最后增加一个新结点的函数的调用(Y-1,N-0)**/
printf("添加成功!\n");
print_L(head);
break;

case 3:
printf("请输入要添加到链尾的结点的数据: ");
scanf("%d",&data); /**输入要添加的结点的数据*/
if(append_t(head, data)) /**在已存在的链表最后增加一个新结点的函数的调用(Y-1,N-0)**/
printf("添加成功!\n");
print_L(head);
break;

case 4:{
int site;
printf("请输入位序号: ");
scanf("%d",&site);
p = locfda(head, site);
if(p != NULL)
printf("Has find the node!\n其数据为:%d\n", p->data);
else
printf("Don't find the node!\n");
break;
}

case 5:
printf("请输入要求在其后插入新结点的结点的数据: ");
scanf("%d",&data);
locate(head, data, &p);
int isinsert;
printf("请输入新结点的数据: ");
scanf("%d",&data);
isinsert = insert(head, p, data); /**在某结点之后插入一个新结点的函数的调用(Y-1,N-0)**/
if(isinsert)
printf("插入成功!\n");
else
printf("未插入成功!\n");
print_L(head);
break;

case 6:
printf("请输入要删除的结点的位序: ");
int deletesi;
scanf("%d",&deletesi);
int deletend;
if(deletendnd(head,deletesi,&deletend)) /**结点的删除函数的调用**/
printf("删除成功!\n其值为: %d\n", deletend);
else
printf("未删除成功!\n");
print_L(head);
break;

case 7:
printf("请输入要寻找的结点的数据: ");
int islocate;
scanf("%d",&data);
LNode *head_findnode; /*要寻找的结构体的指针*/
islocate = locate(head, data, &head_findnode); /**求某结点的指针的函数的调用**/
if(head_findnode != NULL)
printf("Has find the node!\n其位序为:%d\n", islocate);
else
printf("Don't find the node!\n");
break;

case 8:
if(clear(head))
printf("清空成功!\n");
else
printf("清空失败!\n");
break;

case 9:
printf("请输入要求前驱结点的结点的数据: ");
scanf("%d",&data);
LNode *prep;
locate(head, data, &p);
prep=locatePre(head,p); /**求p所指结点的前驱的函数的调用**/
if(prep==NULL)
printf("Don't find the prenode!\n");
else
printf("Has find the prenode!The data is %d\n",prep->data);
break;

case 10:
printf("%s\n", head->info);
break;

case 11:{
int i;
int batchnum;
int batch[100];
printf("请输入要批量添加的结点的个数: ");
scanf("%d",&batchnum);
printf("请输入各结点的数据(用空格隔开): ");
for(i = 0; i < batchnum; i++)
scanf("%d", batch+i);
if(batchadd(head, batchnum, batch))
printf("批量添加成功!\n");
print_L(head);
break;
}

case 12:
printf("当前链表长度为: %d\n", head->length);
break;

case 13:
print_L(head);
break;

case 14:
reverse(head);
printf("链表逆置后为:\n");
print_L(head);
break;

case 15:
print_hyphen(15);
printf("\n");
printf("再见!\n");
print_hyphen(15);
end = 1;
break;

default:
print_hyphen(15);printf("\n");
printf("无此序号,请重新输入!\n");
print_hyphen(15);printf("\n");
}

}
return 0;
}

/*********************************************************************************************************************/

HNode* createNullList() /**创建空链表的函数的定义**/ { HNode* head; head=(HNode*)malloc(sizeof(HNode)); head->length = 0; if(head!=NULL){ head->next=NULL; printf("Has create null list success!\n"); } else printf("Out of space!\n"); return head; }

int isNullList(HNode *head) /**判断是否链表是否为空的函数的定义(Y-1,N-0)**/ { return head->next==NULL; }

int append_h(HNode *head, int n) /**在已存在的链表最前增加一个新结点的函数的定义(Y-1,N-0)**/
{
LNode *p, *pnew;
pnew = (LNode*)malloc(sizeof(LNode));
if(pnew == NULL){
printf("Out of space!\n");
return 0;
}
pnew->data = n;
pnew->next = head->next;
head->next = pnew;
head->length++;
return 1;
}

int append_t(HNode *head, int n) /**在已存在的链表最后增加一个新结点的函数的定义(Y-1,N-0)**/ { LNode *p, *pnew; pnew=(LNode*)malloc(sizeof(LNode)); if(pnew==NULL){ printf("Out of space!\n"); return 0; } else{ pnew->data = n; p = head->next; /*p先指向头结点*/ if(p == NULL){ /*如果链表为空*/ head->next = pnew; pnew->next = NULL; } else{ while(p->next!=NULL) /*若p所指不是链尾*/ p=p->next; /*p后移一个结点*/ p->next=pnew; /*链尾的next存储新结点指针*/ pnew->next=NULL; /*使新结点成为链尾*/ } head->length++; } return 1; }

int locate(HNode *head, int n, LNode **p) /**求某结点的指针,并返回其位序的函数的定义**/ { int i = 1; *p = NULL; *p = head->next; /*将头结点的next域赋值给p,使指向第一个结点*/ while(*p != NULL && (*p)->data != n){ i++; *p = (*p)->next; } if(*p == NULL) return 0; return i; }

LNode* locatePre(HNode *head, LNode *p) /**求p所指结点的前驱的函数的调用**/ { LNode *ptemp; ptemp = head->next; while(ptemp != NULL && ptemp->next != p) ptemp = ptemp->next; return ptemp; }

LNode* locfda(HNode *head, int n) /**查找某位序的元素的数据的函数的定义**/
{
LNode *p = head->next;
if(n < 1 || n > head->length)
return NULL;
while(n > 1 && p != NULL){
p = p->next;
n--;
}
if(n > 1)
return NULL;
else
return p;
}

int insert(HNode *head, LNode *p, int n) /**在某结点之后插入一个新结点的函数的定义(Y-1,N-0)**/
{
LNode *pnew = (LNode*)malloc(sizeof(LNode));
if(pnew == NULL){
printf("Out of space!\n");
return 0;
}
pnew->data = n;
pnew->next = p->next;
p->next = pnew;
head->length++;
return 1;
}

int batchadd(HNode *head, int n, int *s) /**批量添加结点的函数的定义**/
{
LNode *p, *pnew;
int i;
p = head->next;
if(head->next == NULL){
pnew=(LNode*)malloc(sizeof(LNode));
if(pnew==NULL){
printf("Out of space!\n");
return 0;
}
pnew->data = s[0];
head->next = pnew;
pnew->next = NULL;
p = pnew;
head->length++;
i = 1;
}
else{
while(p->next != NULL)
p = p->next;
i = 0;
}
while(i < n){
pnew=(LNode*)malloc(sizeof(LNode));
if(pnew==NULL){
printf("Out of space!\n");
return 0;
}
pnew->data = s[i];
pnew->next = NULL;
p->next = pnew;
p = pnew;
i++;
head->length++;
}
return 1;
}

int deletendnd(HNode *head, int i, int *e) /**结点的删除函数的定义**/ { int j = 0; LNode *p, *q; p = head->next; if(i == 1){ j = 1; head->next = p->next; *e = p->data; free(p); return 1; } while(p->next != NULL && j < i-2){ p = p->next; j++; } if(!(p->next) || j > i-2) return 0; q = p->next; p->next = q->next; *e = q->data; free(q); head->length--; return 1; }

int clear(HNode *head)
{
LNode *pa, *pb;
pa = pb = head->next;
while(pa != NULL && pb != NULL){
pb = pa->next;
free(pa);
pa = pb->next;
free(pb);
}
return 1;
}

void reverse(HNode *head) /**单链表的就地逆置函数的定义**/
{
LNode *p, *q;
p = head->next;
head->next = NULL;
while(p != NULL){
q = p;
p = p->next;
q->next = head->next;
head->next = q;
}
}

void print_L(HNode *head)
{
printf("\n当前链表中的数据为:\n");
LNode *p = head->next;
while(p != NULL){
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}

void print_hyphen(int n)
{
while(n--)
printf("-");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息