线性表的链式表示和实现(数据结构课本2.3节)

对于线性表的链式存储可以用一组任意的存储单元来存储数据元素。

通过结构体构造一个特殊类型“结点”,他本身包含一个数据变量用于存储本身的数据信息,另外也包含一个结点类型的指针变量用于存储相邻结点的地址信息,这样就可以通过地址域实现任意结点的链接。没有了顺序存储所具有的弱点。

遇到的问题:

       1>对于创建具有多个结点的链表(这里是基于课本运用的头插法,代码注释中有尾插法,输入为正序),创建的第一个结点放在了链表的最后端,然后依次将结点向前链接,这样就导致我们输入的数据逆序排列,为了达到要求的输出效果,我们需要变换输入方式。例如输入一组非递减的数据,我们在输入的时候就要将元素以递减的方式输入,下面的代码就是以这种方式。

       2>头结点的数据域为空,在编程的时候一定要分清本身结点和下一个结点,如果初始化定义的结点变量的是头结点,必须指向它的下一个结点取数据,这样定义容易出错,所以在申明结点变量时直接将非头结点的第一个结点赋给变量,这样在后续操作就不容易出错。

       3>在链表的操作中没用的结点要记得释放。

内容的详细理解都标注在代码的注释中

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define OK 1
#define TRUE 1
#define ERROR 0
#define FALSE 0
#define LIST_INIT_SIZE 100 
#define LISTINCREMENT 10 
typedef int Status;
typedef Status ElemType;
typedef ElemType * List;
typedef struct	LNode{
	ElemType data;                  //每一个结点的数据域 
	struct LNode *next;             //每一个结点的指针域:存放下一个结点的地址,实现环环相扣; 
}LNode, *LinkList; 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
void MergeList(LinkList &L1,LinkList &L2,LinkList &L3);
void CreateList(LinkList &L,ElemType n);
Status ListInsert(LinkList &L,ElemType i,ElemType e);
Status ListDelete(LinkList &L,ElemType i,ElemType &e);
int main(int argc, char *argv[]) {
	LinkList L1;
	LinkList L2;
	LinkList L3;
	Status i,m,n,u; 

	printf("创建链表L1的长度为:");
	scanf("%d",&n); 
	printf("输入链表各结点的数据:"); 
	CreateList(L1,n);
	printf("\n");
	
	
	LinkList b5=L1->next;  
    printf("/********切记链表的创建是将结点依次插入链表的尾端向前递进********/\n");
    printf("/********依次表现为输入的次序与列表显示的次序是相反的*******/\n");
	printf("请输出创建好的链表1:");
	for(i=0;i<n;i++){
	printf(" %d ",b5->data);
	b5=b5->next;
	} 
	printf("\n");
	
	//测试:ListInsert函数;
	LinkList a1=L1->next;                      //从第一个数据域不为空的结点开始 
	printf("测试:在L1链表的第三个结点前插入数据域为5的结点;\n"); 
    if(ListInsert(L1,3,5)){
	    printf("请输出插入后的队列:");
		for(i=0;i<=n;i++){
		printf(" %d ",a1->data);
		a1=a1->next;
		} 
	}
	printf("\n");
	
   	//测试:ListDelete函数;
   	LinkList b1=L1->next;
	printf("测试:删除L1链表的第三个结点:\n");
	if(ListDelete(L1,3,u)){
		printf("删除结点的数据为:%d\n",u);
		}
		printf("请输出删除后的队列:");
		for(i=0;i<n;i++){
		printf(" %d ",b1->data);
		b1=b1->next;
		} 
	printf("\n");
	printf("\n");
	printf("创建链表L2的长度为:");
	scanf("%d",&m); 
	printf("输入链表各结点的数据:"); 
	CreateList(L2,m);
	printf("\n");
	
	MergeList(L1,L2,L3);
	LinkList a3=L3->next;
	LinkList a4=L3->next;
	ElemType q=0;
	while(a4){
		q++;
		a4=a4->next;
	}
	printf("新链表结点的个数:%d\n",q); 
	printf("请输出归并后L3的元素序列:"); 
	for(i=0;i<q;i++){
		printf(" %d ",a3->data);
		a3=a3->next;
		}
	printf("\n");       	
	return 0;
}
//头插法 逆序
void CreateList(LinkList &L,ElemType n){          //创建一个长度为n的单链表 
	ElemType i;
	L=(LinkList)malloc(sizeof(LNode));            //申请一个结点大小的地址空间 
	L->next=NULL;
	LinkList p;                                   //创建一个结点类型的变量(本质是一个结点的地址) 
	//总体链表创建的过程是逆着进行,先创建最后一个结点,依次在该结点的前边添加新结点。 
	for(i=n;i>0;i--){
		p=(LinkList)malloc(sizeof(LNode));
		scanf("%d",&(p->data));                     //为增加的结点添加数据域 
		p->next=L->next;                          //将新结点插入到表头 
		L->next=p;                                //因为头结点仅仅是一个用于添加新结点的存储器,所以每次头结点的指针域都在改变。               
	} 	
} 
 
//尾插法:正序 
/*void CreateList(LinkList &L,ElemType n){          
	ElemType i;
	L=(LinkList)malloc(sizeof(LNode));        
	L->next=NULL;
	LinkList p,q;   
	q=L;                              
	for(i=0;i<n;i++){
		p=(LinkList)malloc(sizeof(LNode));
		p->next=NULL;
		scanf("%d",&(p->data));                                          
		q->next=p; 
		q=q->next;                               
	} 	
} 
*/ 

Status ListInsert(LinkList &L,ElemType i,ElemType e){          //在L的第i个元素前插入元素e 
	LinkList p=L;                               //初始化头节点 
	ElemType j=0;
	while(p&&j<i-1){                        //寻找第i个结点的前一个结点 
		p=p->next;                          //循环完成找到第i-1个结点 
		++j;
	} 
	if(!p||j>i-1)    return ERROR;     
	LinkList s=(LinkList)malloc(sizeof(LNode));      //增加新结点
	s->data=e;	s->next=p->next;            //新结点的指针域存放原来第i个结点的地址。
	p->next=s;                              //第i-1个结点的指针域存放新节点的地址 
	return OK;          
}

Status ListDelete(LinkList &L,ElemType i,ElemType &e){          //删除链表的第i个结点,用e返回该节点的值。 
	LinkList p=L;                                //初始化头节点 
	ElemType j=0;
	while(p&&j<i-1){                         //寻找第i个结点的前一个结点 
		p=p->next;                           //循环完成找到第i-1个结点 
		++j;
	} 
	if(!p||j>i-1)    return ERROR;     
	LinkList q=p->next;                      //定义一个结点变量,用来表示即将删除的第i个结点。 
	e=q->data;                               //将删除结点的数据域赋给变量e 
	p->next=q->next;	                     //改变删除结点的前一个结点的指针域 
	free(q);             					 //释放删除结点所占用的空间 
	return OK;          
}

void MergeList(LinkList &L1,LinkList &L2,LinkList &L3){                   //单链表的归并 
	LinkList p1,p2,p3;
	p1=L1->next;
	p2=L2->next;
	L3=p3=L2;                           //这里L1或者L2均可以,只是起到一个头指针赋给L3的作用 
	while(p1&&p2){                      //结束条件有一个链表的指针域为空 
		if((p1->data)<=(p2->data)){
			p3->next=p1;   p3=p1;       p1=p1->next; 
		}else{
			p3->next=p2;   p3=p2;       p2=p2->next;		
		}
	}
	//将剩余结点拼接 
	if(p1){   
	p3->next=p1;
	}               
	if(p2){ 
    p3->next=p2;	
	} 
	free(L1);                    //释放列表1的头结点 
}




运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值