线性表之单链表学习小结(初学数据结构必看)

花了好几个小时,详细规划出了整个过程,包括所有基本操作。。。有什么疑问请下方留言

#include<iostream>
using namespace std;

#define ElemType char
#define ERROR 0
#define OK 1
typedef struct Node
{
	ElemType data;
	struct Node *next;
}Node,*LinkList;

void init_linklist(LinkList L)/*对单链表进行初始化*/
{
	L=(Node*)malloc(sizeof(Node)); /*申请结点空间*/
	L->next=NULL;                      /*置为空表*/
}

void CreateFromHead(LinkList   L)
{
	Node *s;
	char 	c;
	int 	flag=1,k=0;
	while(flag)   /* flag初值为1,当输入"$"时,置flag为0,建表结束*/
	{
		c=getchar();
		if(c!='$')
		{
			s=(LinkList)malloc(sizeof(Node)); /*建立新结点s*/
			s->data=c;
			s->next=L->next;/*将s结点插入表头*/
			L->next=s;
			if(k==0)
			{k=1;s->next=NULL;}          //具体为啥不知道,但数据结构课程源程序的确是的结尾指向不为空,通过k标记,使得结尾为空
		}
		else
			flag=0;
	}
}

void CreateFromTail(LinkList L)
{
	Node *r, *s;
	char c;
	int   flag =1; /*设置一个标志,初值为1,当输入"$"时,flag为0,建表结束*/
	r=L;                /*r指针动态指向链表的当前表尾,以便于做尾插入,其初值指向头结点*/
	while(flag)         /*循环输入表中元素值,将建立新结点s插入表尾*/
	{
		c=getchar();
		if(c!='$')
		{
			s=(Node*)malloc(sizeof(Node));
			s->data=c;
			r->next=s;
			r=s;
		}
		else
		{
			flag=0;
			r->next=NULL;   /*将最后一个结点的next链域置为空,表示链表的结束*/
		}
	}
}
ElemType Get (LinkList  L, int i)
/*在带头结点的单链表L中查找第i个结点,若找到(1≤i≤n),则返回该结点的存储数值; */
{
	int j;
	Node  *p;
	p=L;
	j=0;   /*从头结点开始扫描*/
	while ((p->next!=NULL)&&(j<i))
	{
		p=p->next;    /* 扫描下一结点*/
		j++;   /* 已扫描结点计数器 */
	}
	if(i == j)
		return p->data;   /* 找到了第i个结点 */
	else
		return NULL;   /* 找不到,i≤0或i>n */
}
int Locate( LinkList L,ElemType key)
/*在带头结点的单链表L中查找其结点值等于key的结点,若找到则返回该结点的位置p,否则返回NULL*/
{
	Node *p;
	int k=1;
	p=L->next;    /*从表中第一个结点开始 */
	while (p!=NULL)
	{
		if (p->data!=key)
			p=p->next;
		else
			break; /*找到结点值=key时退出循环 */
		k++;
	}
	return k;
} 

int	ListLength(LinkList L)
/*求带头结点的单链表L的长度*/
{
	Node *p;
	int j;
	p=L->next;
	j=0;   /*用来存放单链表的长度*/
	while(p!=NULL)
	{
		p=p->next;
		j++;
	}
	return j;	/*j为求得的单链表长度*/
}  

int InsList(LinkList L,int i,ElemType e)
/*在带头结点的单链表L中第i个位置插入值为e的新结点*/
{
	Node *pre,*s;
	int k;
	if(i<=0)return ERROR;
	pre=L;
	k=0;                     /*从"头"开始,查找第i-1个结点*/
	while(pre!=NULL&&k<i-1)  /*表未查完且未查到第i-1个时重复,找到pre指向第i-1个*/
	{
		pre=pre->next;
		k=k+1;
	}									/*查找第i-1结点*/
	if(!pre)      /*如当前位置pre为空表已找完还未数到第i个,说明插入位置不合理*/
	{
		printf("插入位置不合理!");
		return ERROR;
	}
	s=(Node*)malloc(sizeof(Node));   /*申请一个新的结点S */
	s->data=e;                       /*值e置入s的数据域*/
	s->next=pre->next;				/*修改指针,完成插入操作*/
	pre->next=s;
	return OK;
}
int DelList(LinkList L,int i,ElemType *e)
/*在带头结点的单链表L中删除第i个元素,并将删除的元素保存到变量*e中*/
{
	Node *pre,*r;
	int k;
	pre=L;
	k=0;
	while(pre->next!=NULL && k<i-1)	/*寻找被删除结点i的前驱结点i-1使p指向它*/
	{
		pre=pre->next;
		k=k+1;
	}								/*查找第i-1个结点*/
	if(!(pre->next))     /* 即while循环是因为p->next=NULL或i<1而跳出的,而是因为没有找到合法的前驱位置,说明删除位置i不合法。*/
	{
		printf("删除结点的位置i不合理!");
		return ERROR;
	}
	r=pre->next;
	pre->next=pre->next->next;    /*修改指针,删除结点r*/
	*e = r->data;
	free(r);    /*释放被删除的结点所占的内存空间*/
	printf("成功删除结点!");
	return OK;
}
LinkList MergeLinkList(LinkList LA, LinkList LB)
/*将递增有序的单链表LA和LB合并成一个递增有序的单链表LC*/
{
	Node *pa,*pb;
	Node *r;
	LinkList LC;
	/*将LC初始置空表。pa和pb分别指向两个单链表LA和LB中的第一个结点,r初值为LC*/
	pa=LA->next;
	pb=LB->next;
	LC=LA;
	LC->next=NULL;
	r=LC;
	/*当两个表中均未处理完时,比较选择将较小值结点插入到新表LC中。*/

	while(pa!=NULL && pb!=NULL)
	{
		if(pa->data <= pb->data)
		{
			r->next=pa;
			r=pa;
			pa=pa->next;
		}
		else
		{
			r->next=pb;
			r=pb;
			pb=pb->next;
		}
	}
	if(pa) /*若表LA未完,将表LA中后续元素链到新表LC表尾*/
		r->next=pa;
	else	 /*否则将表LB中后续元素链到新表LC表尾*/
		r->next=pb;
	//	free(LB);         原文是这么写的,不过释放失败,原因请看我的博客"浅析C语言malloc与free"

	return(LC);
}
void print(LinkList L)
{
	LinkList p=L->next;
	int i=0;
	while(p!=NULL)
	{
		cout<<p->data<<"  ";
		p=p->next;
	}
	cout<<endl;
}
int main()
{
	Node LA,LB;
	LinkList LC;
	int n;
	ElemType key;
	init_linklist(&LA);
	init_linklist(&LB);

	cout<<"以尾插法建立链表LB:(输入$结束)"<<endl;
	CreateFromTail(&LA);
	print(&LA);

	cout<<"以头插法建立链表LB:(输入$结束)"<<endl;
	CreateFromHead(&LB);
	print(&LB);

	cout<<"在LA中按序号查找某元素输出值"<<endl;
	cin>>n;
	cout<<Get (&LA,n)<<endl;

	cout<<"在LA中按值查找某元素输出序号"<<endl;
	cin>>key;
	cout<<Locate(&LA,key)<<endl;

	cout<<"求LA表的节点长度:"<<endl;
	cout<<ListLength(&LA)<<endl;

	cout<<"在LA表中插入数e(输入位置和e,注意此时的ElemType是char类型,最大支持读入9)"<<endl;
	cin>>n;
	cin>>key;
	if(InsList(&LA,n,key))
	{
		cout<<"插入成功!"<<endl;
		print(&LA);
	}
	else
		cout<<"插入失败!"<<endl;

	cout<<"在LA表中删除第i个元素(输入位置i)"<<endl;
	cin>>n;
	if(DelList(&LA,n,&key))
		cout<<"删除的元素为:"<<key<<endl;
	else
		cout<<"删除失败!"<<endl;

	cout<<"合并LA,LB后的链表为:"<<endl;
	LC=MergeLinkList(&LA,&LB);
	print(LC);
	return 0;
}

附带:循环链表的合并算法

LinkList   merge_1(LinkList LA,LinkList LB)
{  /*此算法将两个采用头指针的循环单链表的首尾连接起来*/
	Node *p, *q;
	p=LA;
	q=LB;
	while (p->next!=LA)	p=p->next;	/*找到表LA的表尾,用p指向它*/
	while (q->next!=LB)	q=q->next;	/*找到表LB的表尾,用q指向它*/
	q->next=LA;	/*修改表LB 的尾指针,使之指向表LA 的头结点*/
	p->next=LB->next; /*修改表LA的尾指针,使之指向表LB 中的第一个结点*/
	free(LB);
	return(LA);
}
LinkList  merge_2(LinkList RA,LinkList RB)
{  /*此算法将两个采用尾指针的循环链表首尾连接起来*/
	Node *p;
	p=RA->next; /*保存链表RA的头结点地址*/
	RA->next=RB->next->next;/*链表RB的开始结点链到链表RA的终端结点之后*/
	free(RB->next);/*释放链表RB的头结点*/
	RB->next=p;/*链表RA的头结点链到链表RB的终端结点之后*/
    return  RB;/*返回新循环链表的尾指针*/
}

双向链表的插入与删除

int DlinkIns(DoubleList L,int i,ElemType e)
{
	DNode  *s,*p;
	int k;
	p=L;
	k=0;                     /*从"头"开始,查找第i-1个结点*/
	while(p->next!=L&&k<i)  /*表未查完且未查到第i-1个时重复,找到p指向第i个*/
	{
		p=p->next;
		k=k+1;
	}									/*查找第i-1结点*/
	if(p->next == L)      /*如当前位置p为空表已找完还未数到第i个,说明插入位置不合理*/
	{
		printf("插入位置不合理!");
		return ERROR;
	}
	s=(DNode*)malloc(sizeof(DNode));
 	if (s)
	{
		s->data=e;
		s->prior=p->prior;
		p->prior->next=s;
		s->next=p;
		p->prior=s;
		return OK;
	}
	else
		return ERROR;
}
int	DlinkDel(DoubleList L,int i,ElemType *e)
{
	DNode  *p;
	int k;
	p=L;
	k=0;                     /*从"头"开始,查找第i个结点*/
	while(p->next!=L && k<i)  /*表未查完且未查到第i个时重复,找到p指向第i个*/
	{
		p=p->next;
		k=k+1;
	}
	if(p->next == L)
	{
		return ERROR;
	}
	else
	{
		*e=p->data;
		p->prior->next=p->next;
		p->next->prior=p->prior;
		free(p);
		return OK;
	}
}

静态链表的初始化,节点分配&回收

void initial(StaticList space, int *av)
{
    int k;
	space[0].cursor=0;      /*设置已用静态单链表的头指针指向位置0*/
	for(k=0;k<Maxsize-1;k++)
		space[k].cursor=k+1;    /*连链*/
	space[Maxsize-1].cursor=0;    /*标记链尾*/
	*av=1;  /*设置备用链表头指针初值*/
}
int getnode(StaticList space, int *av)
/*从备用链表摘下一个结点空间,分配给待插入静态链表中的元素*/
{
	int i;
	i=*av;
	*av=space[*av].cursor;
	return i;
}
void   freenode(StaticList space, int *av, int k)
/*将下标为 k的空闲结点插入到备用链表*/
{
	space[k].cursor=*av;
	*av=k;
}
时间: 2024-10-09 07:43:29

线性表之单链表学习小结(初学数据结构必看)的相关文章

线性表——顺序表与单链表学习小结

线性表 线性表(linear list)是n个具有相同特性的数据元素的有限序列. 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表.链表.栈.队列.字符串... 线性表在逻辑上是线性结构,也就说是连续的一条直线.但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储. 顺序表 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储.在数组上完成数据的增删查改. 链表 链表是一种物理存储结构上非连续.非顺序的存储结构,数据

续上文----线性表之单链表(C实现)

本文绪上文线性表之顺序表(C实现) 本文将继续使用单链表实现线性表 的另外一种存储结构.这种使用 链表实现的存储结构在内存中是 不连续的. C实现代码如下: #include<stdio.h> typedef struct node { int data; struct node *next; }Node; //链表的初始化 Node* InitList(int number) { int i; Node *pHead=(Node *)malloc(sizeof(Node)); Node *T

[大话数据结构]线性表之单链表结构和顺序存储结构

线性表定义: 零个或者多个数据元素的有限序列.元素之间是有顺序的,如果元素存在多个,则第一个元素无前驱,最后一个元素无后继.其他每个元素都有且只有一个前驱和后继.并且数据元素的类型要相同. 线性表的抽象数据类型: ADT 线性表(List) Data 线性表的数据对象集合为{a1,a2,...,an},每个元素的类型均为DataType. 其中,除第一个元素a1外,每一个元素有且只有一个直接前驱元素,除了最后一个元素an外,每一个元素有且只有一个直接后继元素. 数据元素之间的关系是一对一的关系.

数据结构学习总结(2) 线性表之单链表

一,回忆链表 链表,别名链式存储结构或单链表,用于存储逻辑关系为 "一对一" 的数据.与顺序表不同,链表不限制数据的物理存储状态,换句话说,使用链表存储的数据元素,其物理存储位置是随机的. 例如,使用链表存储 {1,2,3},数据的物理存储状态如图 1 所示: 图 1 链表随机存储数据 我们看到,图 1 根本无法体现出各数据之间的逻辑关系.对此,链表的解决方案是,每个数据元素在存储时都配备一个指针,用于指向自己的直接后继元素.如图 2 所示: 图 2 各数据元素配备指针 像图 2 这样

数据结构:线性表之单链表

线性表(亦作顺序表)是最基本.最简单.也是最常用的一种数据结构.线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的.线性表有两种存储结构: ①顺序存储结构,即存储单元在一段连续的地址上存储,常见的数组就是顺序存储结构的线性表: ②链式存储结构,即存储单元在不连续的地址上存储.因为其不连续性,除了要存数据元素信息(数据域)外,还要存储它后继元素(结点)的地址(指针域,链).学习链式结构最好将结点结构牢记于心,如下图: 链表的每个结点只含有一个指

Java数据结构-线性表之单链表LinkedList

线性表的链式存储结构,也称之为链式表,链表:链表的存储单元可以连续也可以不连续. 链表中的节点包含数据域和指针域,数据域为存储数据元素信息的域,指针域为存储直接后继位置(一般称为指针)的域. 注意一个头结点和头指针的区别: 头指针: 指向链表的第一个节点的指针,若链表有头结点,则是指向头结点的指针: 头指针具有标识作用,所以常用头指针作为链表的名字: 不论链表是否为空,头指针都不为空: 是链表的必要元素. 头结点: 头结点是为了操作的统一和方便而设立的,放在第一个元素节点的前面,其数据域一般无意

【Java】 大话数据结构(2) 线性表之单链表

本文根据<大话数据结构>一书,实现了Java版的单链表. 书中的线性表抽象数据类型定义如下(第45页): 实现程序: package LinkList; /** * 说明: * 1.<大话数据结构>中没有线性表的长度,但提到可以存储于头节点的数据域中. * 本程序的线性表长度存放于count变量中,线性表长度可以使程序比较方便. * 2.程序中,第i个位置代表第i个结点,头结点属于第0个结点 * 3.因为链表为泛型,整表创建采用整型(随机整数做元素),所以有出现一些类型转换 * 4

线性表的单链表的定义、初始化等操作

#include <stdio.h> #include <stdlib.h> #define OK 1 #define ERR 0 #define MAXSIZE 100 typedef int ElemType; //定义 typedef struct Node { ElemType data; struct Node *next; }Node,*LinkedList; //初始化 LinkedList LinkedListInit() { Node *L; L = (Node

线性表之单链表实现一元多项式相加

一元多项式定义: 设a0,a1,a2,-,an-1,an都是数域F中的数(注:1,2,--,n-1,n均为a的下角标),n是非负整数,那么表达式 anx^n +an-1x^(n-1)+-+a2x^2 +a1x + a0(an≠0) (1) 叫做数域F上一个文字x的多项式或一元多项式.在多项式(1)中,a0叫做零次多项式或常数项,a1x叫做一次项,一般,aix叫做i次项,ai叫做i次项的系数.一元多项式用符号f(x),g(x),-来表示. 说一下思路,利用带有两个数据元素的链表实现加法运算,数据域