数据结构与算法(五)--链表的实现

                                              线性表的链式存储

单链表的定义:

链表是一种物理存储单元上非连续、非顺序的存储结构数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

Typedef struct LNode{
	ElemType data;    //数据域
	struct LNode *next;    //指针域
}LNode, *LinkList;
  1. 建立单链表

设节点的数据类型是整型动态建立单链表的方法有头插式和尾插式

头插式: 从一个空表开始,重复读入数据,生成新节点,将读入数据存放到新节点的数据域,然后将新节点插入到当前链表的头部,直到读入结束标记为止,每次插入的节点都作为链表的第一个节点。

头插节点算法图解:   

          

算法实现:

LNode *createLinkedList(void)		//链表节点头插式
{	
    int data;
	LNode *head , *p;		//创建头节点和节点p
	head = (LNode *)malloc(sizeof(LNode));	//动态分配内存空间
	head->next = NULL;		//初始头指针指向空
    while(1)
    {	
	    scanf(“%d”,&data);
	    if(data>=32767)	break;
		    p = (LNode *)malloc(sizeof(LNode);		//给节点p分配存储单元
		    p->data = data;				
		    p->next = head->next;			//将p节点的后继指向为原头指针的后继元素
		    head->next = p;				//将头指针指向p节点
    }
	return (head);		//返回这个链表
}

尾插式: 将新节点插入到当前链表的表尾,使其成为当前链表的尾节点。

链表节点尾插式算法描述:

LNode *createLinkedList(void)		//链表节点头插式
{	
int data;
		LNode *head ,* last, *q;		//创建头指针和尾指针和节点q
		head = q = (LNode *)malloc(sizeof(LNode));	//动态分配内存空间
		q->next = NULL;		//创建单链表的表头节点head
		while(1)
		{	
			scanf(“%d”,&data);
		if(data>=32767)	break;
			q = (LNode *)malloc(sizeof(LNode);		//给节点q分配存储单元
			q->data = data;		//数据域赋值
			q->next = last->next;	//将q节点指向last原指向(可换作倒数第二行)
			last->next = q;	//尾节点指向插入的节点q
			last = q;			//插入的节点变成尾节点(后移一位)
		}
	//last->next = NULL;
	return	(head);
} 

如果插入建立单线性链表的节点是n个,算法时间复杂度为O(n)

链表的CRUD操作的实现:

按序号查找节点值:

LNode *LocateElem (LNode * L , int e)
{	
    int j =1; LNode *p;
    *p = L->next;
	while(p! = NULL && j<i){
	    p = p->next;
		j++;
		if( j != i)
			return NULL;
		else
			return  (p->data);
    }
}

 按值查找链表节点:

LNode *Locate_Node(LNode *L , int key)
{	
    LNode *p = L-next;
	while(p!=NULL&&p->data!=key){
	    p = p->next;
		if(p->data == key)
			return p;
		else
			return NULL;
    }		
}

该算法时间复杂度与形参key值有关,平均时间复杂度为O(n)

  1. 单链表的插入:

插入运算是将值为e的新节点插入到表的第i个节点的位置上,即插入到ai-1ai之间。所以必须首先找到ai-1所在的节点p,然后生成一个数据域为e的新节点qq节点作为p的直接后继节点

单链表各种操作的具体实现:

#include<stdio.h>
//定义单链表
typedef struct LNode{
	ElemType data;
	struct LNode *next; 
} LNode, *LinkList;

LinkeList CreatList1(LinkList &L)	//头插法建立单链表 
{
	LNode *s;
	int x; 
	L = (LinkList *)malloc(sizeof(LNode));	//动态分配内存空间 
	L->next = NULL;		//头节点指向空 
	scanf("%d",&x);
	while(x!=9999)
	{
		s = (LNode *)malloc(sizeof(LNode));
		s->data = x;
		s->next = L->next;	
		L->next = s;
		scanf("%d",&x);
	}
	return L;
}

LinkList *CreatList2(LinkList &L)	//尾插法建立单链表 
{
	LNode *s;                    //在末尾准备插入的结点
	LNode *r = L;                //定义尾指针
	int x;
	L = (LinkList *)malloc(sizeof(LNode));    //动态分配内存空间 
	scanf("%d", &x);
	while(x!=9999)
	{
		s = (LNode *)malloc(sizeof(LNode));    //最后插入的节点分配空间
		s->data = x;        
		r->next = s;		//在尾结点r的后面插入节点s 
		r = s;				//尾结点的指针指向s节点 
		scanf("%d", &x);
	}
	r->next = NULL;			//最后的节点一定要指向NULL 
	return L;
}

LNode *GetElem(LinkList L, int i)		//按序号i查找元素 
{
	int j = 1;
	LNode *p = L->next;		//初始化指针p为头指针 
	if(i==0)
	{
		return L;			//返回头节点 
	}	
	else if(i<1)
	{
		return NULL;		//情况不存在 
	}
	while(p&&j<i)
	{
		p = p->next;		//指针p向后指向 
		j++;				//计数器j往后移一位 
	}
	return p;				//返回当前节点 
} 

LNode *LocateElem(LinkList L, ElemType e)	//按值查找节点 
{
	LNode *p = L->next;
	while(p != NULL && p->data != e) 
	{
		p = p->next;		//链表往后移动查找 
	}
	return p;
}

LNode *CountLength(LinkList L,int x)	//求单链表的长度 
{
	LNode *p = L->next;
	int i=0;
	while(1)
	{	
		p->next = p;
		i++;
	}
	return i;
}

void main()
{
	LinkList *p,*q,*s;		//s是待插节点,再定义一个临时节点p	
	/****前插法插入节点****/
	p = GetElem(L, i-1);		//找到i-1位置的节点 p (待插节点的前驱结点) 
	s->next = p->next;		// 将p的原指向转给s 
	p->next = s;			//p指向s,即s在p节点(i-1)位置的后面 i的位置 
	/****后插法插入节点****/ 
	p = GetElem(L, i); 		//找到i位置的节点 p (待插节点的位置)
	s->next = p->next;	//交换指向 ,s节点就到了p节点(i位置)的后面i+1的位置 
	p->next = s;		 
	int temp;					//用临时变量交换data值 
	temp = p->data;			//实现i和i+1位置节点值的交换 
	p->data = s->data;
	s->data = temp; 
	/****删除节点的操作****/ 
	p = GetElem(L,i-1);		//查找目标位置之前的节点p 
	q = p->next;				//q是目标删除节点 ,在p节点后面 
	p->next = q->next;		//断开链接 ,将q原指向直接由p节点指向 
	free(q);					//释放节点的存储空间 
	/****删除节点的骚操作****/
	p = GetElem(L,i-1);
	q = p->next;				//q指向*p节点的后继(i位置) 
	p->data = q->next->data;	//将p的数据域和q节点的后继元素(i+1)的数据域交换 
	p->next = q->next;		//指针q的指向交给了p的指向,实现了断链 
	free(q);
}

 

发布了58 篇原创文章 · 获赞 31 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_37504771/article/details/104261537