数据结构(二)线性表(链表实现的功能)

链表

链接表是线性表的链接储存表示。
特点:
每个元素(表项)由结点(Node)构成。
一个元素有8byte;
4byte的数据,4byte的指针(存放下一个节点的地址)
4byte date | link 4byte
线性结构 :
结点可以连续,可以不连续存储
结点的逻辑顺序与物理顺序可以不一致
表可扩充
在这里插入图片描述

头文件

#ifndef LINKLIST_H
#define LINKLIST_H

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

#define SUCCESS 10000
#define FAILURE  10001

typedef int ElemType;  //把int整形名字改为ElemType(主要是元素) 方便书写

struct Node
{
	ElemType data;         //数据域
	struct Node *next;   //定义一个指针指向结构体struct Node(指针域)
};
typedef struct Node node;  //改名字,把struct Node 改为 node。方便书写
typedef  struct  Node *pNode; //把struct Node * 改为pNode (它是一个指针)

int InitLink(pNode *h);
int InsertLink(pNode h, int p, int num);
int TraverseLink(pNode h);
int GetElem(pNode h, int p);
int LocateElem(pNode h, int e);
int LengthLink(pNode h);
int PriorElem(pNode h, int num);
int NextElem (pNode h, int num);
void ReverseLink(pNode h);
int LinkDel (pNode h, int p);
int ClearLink(pNode h);
int DestoryLink(pNode *p);
#end

子函数,调用函数文件

#include "LinkList.h"  //头文件(自己建立的链表的)
/*
函数描述: 链表初始化
函数参数: 链表头指针的地址
函数返回值: 成功返回SUCCESS,失败返回FAILURE;
*/
int InitLink(pNode *h)
{
	if(NULL == h)  //入参判断
	{
		return FAILURE;
	}
*h = malloc(sizeof(node) * 1);
if(NULL == *h)
{
	return FAILURE;
}
(*h) -> next = NULL;  //定义好头节点, 把下一个节点定义为空。
return SUCCESS;
}
/*
函数描述:链表指定位置插入数据
函数参数:链表头指针   插入的位置  插入的数据
函数返回值: 成功返回SUCCESS   失败返回FAILURE
*/
int InsertLink(pNode h, int p, int num)
{
	if(NULL == h)  //入参判断
	{
		return FAILURE;
	}
	pNode t = h;   //把头节点的地址给 t
	int k = 1;  //定义指针移动次数
	while(k < p && t != NULL)  //把指针移动到要插入位置的前一个位置
	{
		t = t  -> next;
		k++;
	}
	if(t == NULL || k > p) //p的值太大 或者 p的值太小
	{
		return FAILURE;
	}
	pNode n = (pNode)malloc(sizeof(node) * 1);  //为链表插入的元素申请空间。
	if(NULL == n)
	{
		return FAILURE;
	}
	n -> data = num;  //把数据的值传给新元素的数据区域
	n -> next = t -> next;  //把原来前一个的元素的指针域的地址赋予给n的指针域。
	t -> next = n;    //把n的地址赋予给原来前一个元素的指针域,使其指向n这块内存。
	return SUCCESS;
}
/*
函数描述: 遍历链表,打印出其中的元素
函数参数: 链表头指针
函数返回值: 失败返回FAILURE, 成功返回SUCCESS
*/
int TraverseLink (pNode h)
{
	if(NULL ==  h)
	{
		return FAILURE;
	}
	pNodet t = h -> next;  //指向第一个结点
	while(t) // (t != NULL)
	{
		printf("%d ",t -> data);
		t = t -> next;
	}
	printf("\n");
	return SUCCESS;
}
\*
函数描述: 根据位置查找元素 
函数参数: 链表头指针   输入的位置
函数返回值: 失败返回FAILURE,找到返回这个位置的元素
*\
int GetElem(pNode  h, int p)
{
	if(NULL == h)
	return FAILURE;
	if(p <= 0)           //p太小
	return FAILURE;

	int k = 0; 
	pNode t  = h;  //从头节点开始
	while ( k < p && t !=NULL)     //把指针移动到要查找位置的前一个位置
	{
		t = t -> next;
		k++;
	}
	if(!t)          // if(t) == if(t != NULL)  if(!t) === if(t == NULL) 防止p值过大
	{
		return  FAILURE;  
	}
	return t -> data;
}
/*
函数描述: 根据元素查找位置
函数参数: 链表头指针    输入的元素
函数返回值:找不到返回失败FAILURE,查找成功返回这个元素的位置
*/
int LocateElem(pNode h, int e)
{
	if(NULL == h)
	return FAILURE;

	pNode t = h -> next;  //从第一个节点开始
	int i =1;
	while(t)
	{
		if(t -> data == e)
		{
			return i;
		}
		i++;
		t = t -> next;
	}
	 return FAILURE;
}
/*
函数描述: 求出链表的长度
函数参数: 链表头指针
函数返回值: 失败返回FAILURE,成功返回链表的长度
*/
int LengthLink(pNode  h)
{
	if(NULL == h)
	return FAILURE;
	// pNode t = h;  //从头节点开始
	pNode t = h -> next;      //从第一个节点开始
	int i = 0;        
	while (t)
	{
		t = t -> next;
		i++;
	}
	//return i - 1;  //从头节点开始。
	return i;   //按道理来说 i++后输入的值为 i +1,所以要减一。
	但这里因为前面 i = 0,按道理 t指向第一个结点,i应该等于 1。(这里是简化了) 
}
/*
函数描述:查找元素的前驱
函数参数:链表头指针  输入的元素
函数返回值: 找不到返回FAILURE,找到返回这个元素的前驱
*/
int PriorElem(pNode h, int num)
{
	if(NULL== h)
	return FAILURE;
	pNode t =h -> next; //指向第一个节点
	while(t -> next)  //   t -> next != NULL
	{
		if(num  == t -> next -> data)  
//依次比较输入的元素和链表里的元素   因为链表和顺序表不一样,链表是通过指针传输地址,不像顺序表是连续的空间,位置变量能随意前进或者后退。而链表是用指针传输地址,其中指针是位置变量,但指针不能返回。
eg: 数组[i] i是位置,可以进行加减。而指针 *p指向的是一个地址,地址不能加减。而每个链表元素都有一个自己的地址和指针域的下一个元素的地址,只能通过指针p取访问,因此链表的位置变量只能前进,不能后退。
所以要想找到元素的前驱,只能通过前一个元素的指针域取访问下一个元素的数据域,如果相等,则这个元素就是输入元素的前驱,返回这个元素的数据域即可。简单一点说就是找到这个元素的前一个位置,通过指针域去判断元素是否相等。
		{
			return t -> data;
		}
		t = t -> next;
	}    //因为前面已经指向第一个节点了,所以循环里面是从第二个开始判断的。
	return FAILURE;
}
/*
函数描述: 查找元素后继节点
函数参数: 链表头指针  输入的元素
函数返回值:找不到返回失败FAILURE,找到返回这个元素的后继节点 
*/
int NextElem(pNode h, int num)
{
	if(NULL == h)
	return FAILURE;
	pNode t = h -> next;
	while(t -> next)
	{
		if(num == t -> data)  
// 因为是查找后继节点,所以可直接找到元素所在位置,它的下一个元素就是后继节点。因此,直接依次比较输入的元素和链表里的元素、如果相等,说明下一个元素及时后继节点。
		{
			return t -> next ->data;
		}  //
		t = t ->next;
	}
	return FAILURE;
}
/*函数描述:链表翻转,颠倒顺序
	函数参数:链表头指针 
	函数返回值: 无
*/
void ReverseLink(pNode h)
{
	if(NULL == h)
	return ;
	pNode p = h -> next; // 把第一个结点的地址给 p
	h -> next = NULL;  // 把头结点的指针域赋值为空指针
	while(p)
	{
		pNode q = p;   //把p的地址给q
		p = p -> next;  //把 指针p向前移动,指向下一个结点。把下一个结点的地址赋予p
		q -> next = h -> next;  // 把现在的 h -> next的地址赋予q -> next
		h -> next = q;   //把现在p的地址赋予h -> next
	}
}
/*
函数描述:删除指定位置的元素
函数参数: 链表头指针    输入的位置
函数返回值:删除失败返回FAILURE , 删除成功返回删除的元素
*/
int LinkDel(pNode h, int p)
{
	if(NULL == h)
	return FAILURE;
	pNode t = h;
	int k = 1; 指针移动的次数
	while(k < p && t != NULL)  //把指针移动到要删除位置的前一个位置
	{
		t = t ->next;
		k++;
	}
	if(t == NULL || k > p || !(t -> next)) // p的值过大或着p的值太小
	{
		return FAILURE;
	}  //无法删除最后一个结点
	pNode n = t -> next;  // 要删除的结点
	int e = n -> data;
	t -> next = n -> next;
	free(n); //释放链表元素申请的空间
	return e;
}
/*
函数描述:清空链表
函数参数: 链表的头指针
函数返回值:失败返回FAILURE,成功返回SUCCESS
*/
int ClearLink(pNode h)
{
	if(NULL == h)
	return FAILURE;
	pNode t =h -> next;
	while(t)
	{
		h -> next = t -> next; //把第一个节点的指针域给h的指针域
		free(t);  //释放第一个结点的空间。
	 	t = h ->text ;  //指针移向下一个结点
}
return SUCCESS;
}
/*
函数描述:清除链表
函数参数:链表头指针的地址
函数返回值:失败返回FAILURE,成功返回SUCCESS
*/
int DestoryLink(pNode *p)
{
	if(NULL == h)
	return  FAILURE;
	free(*h); 释放链表头指针本身的地址空间
	*h ==  NULL;//让头指针中包含的地址为空(赋值为空指针)
	return SUCCESS;
}

主函数文件

#include "LinkList.h"
int main()
{
	srand (time (NULL)); //随机时间随机数字函数
	pNode head = NULL;  //定义链表的头指针
	int ret ;
//链表初始化
	ret = InitLink(&head);
	if(SUCCESS == ret)
	{
		printf("链表初始化成功\n");
	}
	else
	{
		printf("链表初始化失败!\n");
	}
//指定位置插入元素(这里是去全插入,相当于把数据传给链表)
	int i, num;
	for (i =0; i < 7; i++)
	{
		num = rand () %10;
		ret = InsertLink(head, i+1, num); // 尾插法
		// ret = InsertLink(head, 1, num); //头插法	
		if (FAILURE == ret)
		{
			printf("插入元素%d失败\n". num);
		}
		else
		{
			printf("插入元素%d成功\n", num);
		}
	}
//  根据位置查找元素
	int p = 6;
	ret = GetElem(head, p);   //获取指定元素的位置
	if (FAILURE == ret)
	{
		printf("第%d个元素不存在\n", p);
	}
	else
	{
		printf("第%d个元素是%d\n", p, ret);
	}
	//根据元素查找位置
	num = 6;
	ret = LocateElem(head, num);   //返回指定元素的位置
	if(FAILURE == ret)
	{
		printf("元素%d不存在\n", num);
	}
	else
	{
		printf("元素%d是第%d个元素\n", num);
	}

	printf("链表的长度是%d\n", LengthLink(head));
	//根据元素查找元素的前驱
	num = 6;
	ret = PriorElem (head, num); //返回指定元素的前驱
	if(FAILURE == ret)
	{
		printf("%d没有前驱\n", num);
	}
	else
	{
		printf("%d的前驱是%d\n", num, ret);
	}
//根据元素查找元素的后继结点
	num = 6;
	ret = NextElem(head, num);
	if(FAILURE == ret)
	{
		printf("%d没有后继结点\n", num);
	}
	else
	{
		printf("%d的后继结点是%d\n", num, ret);
	}
//删除指定位置的元素
	for(i = 0; i < 3; i++)
	{
		p = rand() %4;  //随机产生一个位置
		ret = LinkDel(head, p);
		if(FAILURE == ret)
		{
			printf("删除第%d个元素失败\n", p);
		}
		else
		{
			prinntf("删除第%d个结点成功,元素是%d\n", p , ret);
		}
	}
	//清空链表
	ret = ClearLink(head);
	if(FAILURE == ret)
	{
		printf("清空链表失败\n");
	}
	else
	{
		printf("清空链表成功\n");
	}
	ret = DestoryLink(&head);
	if(FAILURE == ret)
	{
		printf("清除失败\n");
	}
	else
	{
		printf("清除成功\n");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值