数据结构之线性表(List)(二)

本文详细介绍了单链表和双链表的数据结构,包括它们的定义、基本操作如初始化、判空、求表长、插入、遍历、清空、创建、查找和删除元素,并提供了相应的C语言实现代码。单链表通过指针建立元素间的逻辑关系,而双链表在单链表基础上增加了指向前驱节点的指针,便于双向遍历。
摘要由CSDN通过智能技术生成

目录

1.单链表

1.1单链表的定义

1.2 单链表的基本操作

1.2.1  预备代码

 1.2.2  初始化链表

1.2.3 判空

1.2.4 求表长

1.2.5 整表创建操作(头插法)

1.2.6 遍历元素操作

1.2.7 清空表操作

 1.2.8 整表创建操作(尾插法)

1.2.9 插入元素操作

 1.2.10 按位查找元素操作

1.2.11 按值查找元素操作

1.2.12 删除元素操作

 1.3 单链表实现完整代码:

2.双链表( Double Linked List)

   2.1 基本操作

2.1.1 整表创建(尾插法)

2.1.2 求表长

2.1.3 判空

2.1.4 遍历

2.1.5 清空 

 2.1.6 初始化表

2.1.7  按位插入元素

 2.1.8 按位查找

2.1.9 按值查找

 2.1.10 按位删除

2.2 双链表实现完整代码


tips:本文章只介绍 线性表的链式存储结构!!!

其中,只介绍 单链表 与 双链表 !!!循环链表 和 静态链表 将发布在下个章节!!!

1.单链表

        顺序表可随时存取表中的任意元素,但插入和删除操作需要移动大量元素。链式存储线性表时,不需要使用地址连续的存储单元,即不要求逻辑上相邻的元素在物理位置上也相邻,它通过“链”建立起数据元素之间的逻辑关系。因此插入和删除操作不需要移动元素,只需要修改指针但也会失去顺序表可随机存取的特点

1.1单链表的定义

        线性表的链式存储又称单链表。它是指通过一组任意的存储单元来存储线性表中的数据元素。为了建立数据元素之间的线性关系,对每个链表结点,除存放元素自身的信息外,还需要存放一个指向其后继的指针。

        单链表结点结构如下:

 

         单链表中结点类型的描述如下:

typedef struct LNode
{
    ElemType data;
    struct LNode* next;
}LNode,*LinkList;

  通常用头指针来标识一个单链表,此外,为了操作上的方便,在单链表的第一个结点之前附加一个结点,称为头结点。头结点的数据域可以不设任何信息,也可以记录表长等信息。头结点的指针域指向线性表中的第一个元素结点。

如图:         

                                                         

 

        引入头结点后,可以带来两个优点:

1.由于第一个数据结点的位置被存放在头结点的指针域中,因此在链表的第一个位置上的操作和在表的其他位置的操作一致。

2.无论链表是否为空,其头指针都是指向头结点的非空指针,因此空表和非空表的处理也就得到了统一。

1.2 单链表的基本操作

//初始化表
//判空操作
//求表长操作
//插入元素操作
//遍历元素操作
//清空表操作
//整表创建操作
//按位查找元素操作
//按值查找元素操作
//删除元素操作

1.2.1  预备代码


//线性表的链式存储的实现
#include <stdio.h>
#include <stdlib.h>
#include <time.h>


#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 20

typedef int Status;
typedef int ElemType;

typedef struct Node
{
	ElemType data;
	struct Node* next;

}Node;

typedef struct Node* LinkList;   //定义LinkList

 1.2.2  初始化链表

//初始化链式线性表
Status InitList(LinkList* L)
{
	//开辟内存空间
	*L = (LinkList)malloc(sizeof(Node));  //创建头结点,并让头指针L指向此结点
	if (!(*L))
	{
		return ERROR;
	}
	//头结点指针域置空
	(*L)->next = NULL;
}

1.2.3 判空

/* 初始条件:链式线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
Status ListEmpty(LinkList L)
{
	if (L->next)
	{
		return FALSE;
	}
	else
	{
		return TRUE;

	}
}

1.2.4 求表长

/* 初始条件:链式线性表L已存在。操作结果:返回L中数据元素个数 */
int ListLength(LinkList L)
{
	LinkList p = L->next;
	int i = 0;
	while (p)
	{
		p = p->next;
		i++;
	}

	return i;
}

      上面代码中 p = p->next 的步骤是:p指针访问 “p指针指向的结构体(结点)” 里的成员next,获取next(指针域)里存放的地址,并把该地址赋值给p指针,即让p指针指向下一个结点。

1.2.5 整表创建操作(头插法)

/*  随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
void CreateList_Head(LinkList* L, int n)
{
    srand(time(0));   //初始化随机种子
    //创建一个带头结点的单链表
    (*L) = (LinkList)malloc(sizeof(Node));
    (*L)->next = NULL;
    //在头结点后,循环插入n个随机数
    LinkList p;
    for (int i = 0; i < n; i++)
    {
        //创建新的结点,并让p指向新的结点
        p = (LinkList)malloc(sizeof(Node));
        p->data = rand() % 100 + 1;  //随机生成100以内的数字

        p->next = (*L)->next;   //把头结点后面的结点(第一个结点)的地址 赋值 给新指针p指向结点的指针域
        (*L)->next = p;
    }
}

1.2.6 遍历元素操作

/* 初始条件:链式线性表L已存在 */
/* 操作结果:依次对L的每个数据元素输出 */
Status visit(ElemType c)
{
	printf("%d ", c);
	return OK;
}

void ListTraverse(LinkList L)
{
	LinkList p = L->next;   //指针p指向头结点
	while (p)
	{
		visit(p->data);
		p = p->next;    //指针p指向下一个结点
	}
	printf("\n");
	return OK;
}

 测试代码(对以上的代码进行测试):

 


1.2.7 清空表操作


/* 初始条件:链式线性表L已存在。操作结果:将L重置为空表 */
Status ListClear(LinkList* L)
{
	LinkList p, q;
	//指针p指向第一个结点
	p = (*L)->next;    

	while (p)
	{
		q = p->next;  //指针q指向 p指向结点的 后一个结点(把p指向结点 后一个结点的地址赋值给q)
		free(p);   //释放 p指向的结点
		p = q;     //让指针p指向(新的)第一个结点
	}

	(*L)->next = NULL;   //头结点的指针域置为空
	return OK;
}

        上面代码中,p = (*L)->next 的步骤是:头指针(L)访问其指向的结构体(头结点)里的成员(next),获取next里存放的地址,并把该地址赋值给p。即让p指向 头指针指向结点 的后一个结点。

测试代码 

 

 
1.2.8 整表创建操作(尾插法)

/*  随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
void CreateList_Tail(LinkList* L, int n)
{
	LinkList p, r;  //声明两个结构体指针
	srand(time(0));   //初始化随机种子
	(*L) = (LinkList)malloc(sizeof(Node));   //创建头结点
	r = (*L);    //指针r 指向链表尾部的结点

	for (int i = 0; i < n; i++)
	{
		p = (Node*)malloc(sizeof(Node));  //创建新结点,让p指向新结点
		p->data = rand() % 100 + 1;

		r->next = p;   //把新结点的地址 赋值给 表尾结点的指针域 
		r = p;        //让r指向新的表尾结点
	}

	r->next = NULL;
}

测试代码

1.2.9 插入元素操作

/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(LinkList* L, int i, ElemType e)
{
	LinkList p, s;
	p = (*L);    //p指向头结点
	int j = 1;
	while (p && j < i)   //逻辑与,同真才为真,即需要同时满足两个条件才进入循环
	{
		p = p->next;
		j++;
	}
	if (!p || j > i)   //满足p为空 或 j>i 其中一个条件就进入循环
	{
		return ERROR;
	}

	s = (LinkList)malloc(sizeof(Node));
	s->data = e;
	s->next = p->next;    //把p的后继结点的地址 赋值给 s的指针域
	p->next = s;    //再把s的地址 赋值给 p的指针域

	return OK;
}

测试代码:

 
1.2.10 按位查找元素操作

/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值 */
//按位查找
Status GetElem(LinkList L, int i, ElemType* e)
{
	LinkList p;
	p = L->next;    //指针p指向第一个结点
	int j = 1;             //当查找的元素i为1时,直接返回p指向结点的数据域
	while (p && j < i)   //逻辑与,同真才为真,同时满足两个条件才进入循环
	{
		p = p->next;    //让p指向下一个结点
		j++;
	}
	if (!p || j > i)   //逻辑与,同假为假,即满足其中一个条件,便可进入循环
	{
		return ERROR;
	}
	*e = p->data;

	return OK;
}

 


1.2.11 按值查找元素操作

/* 初始条件:链式线性表L已存在 */
/* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
Status LocateElem(LinkList L, ElemType e)
{
	LinkList p = L->next;  //p指向头结点的后继结点(第一个结点)
	int i = 1;
	while (p)
	{
		if (p->data == e)
		{
			return i;
		}
		else
		{
			p = p->next;
			i++;
		}
	}

	return 0;
}


1.2.12 删除元素操作

 

/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(LinkList* L, int i, ElemType* e)
{
	LinkList p, q;
	p = (*L);  // p指向头结点
	int j = 1;
	while (p->next && j < i)
	{
		p = p->next;
		j++;
	}
	if (!(p->next) || j > i)
	{
		return ERROR;
	}
	q = p->next;
	p->next = q->next;
	*e = q->data;
	free(q);

	return OK;
}

 

 1.3 单链表实现完整代码:

#define _CRT_SECURE_NO_WARNINGS 1


//线性表的链式存储的实现
#include <stdio.h>
#include <stdlib.h>
#include <time.h>


#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 20

typedef int Status;
typedef int ElemType;

typedef struct Node
{
	ElemType data;
	struct Node* next;

}Node;

typedef struct Node* LinkList;   //定义LinkList


//初始化链式线性表
Status InitList(LinkList* L)
{
	//开辟内存空间
	*L = (LinkList)malloc(sizeof(Node));  //创建头结点,并让头指针L指向此结点
	if (!(*L))
	{
		return ERROR;
	}
	//头结点指针域置空
	(*L)->next = NULL;
}

/* 初始条件:链式线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
Status ListEmpty(LinkList L)
{
	if (L->next)
	{
		return FALSE;
	}
	else
	{
		return TRUE;

	}
}


/* 初始条件:链式线性表L已存在。操作结果:返回L中数据元素个数 */
int ListLength(LinkList L)
{
	LinkList p = L->next;
	int i = 0;
	while (p)
	{
		p = p->next;
		i++;
	}

	return i;
}

/*  随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
void CreateList_Head(LinkList* L, int n)
{
	srand(time(0));   //初始化随机种子
	//创建一个带头结点的单链表
	(*L) = (LinkList)malloc(sizeof(Node));
	(*L)->next = NULL;
	//在头结点后,循环插入n个随机数
	LinkList p;
	for (int i = 0; i < n; i++)
	{
		//创建新的结点,并让p指向新的结点
		p = (LinkList)malloc(sizeof(Node));
		p->data = rand() % 100 + 1;  //随机生成100以内的数字

		p->next = (*L)->next;   //把头结点后面的结点(第一个结点)的地址 赋值 给新指针p指向结点的指针域
		(*L)->next = p;
	}
}

/* 初始条件:链式线性表L已存在 */
/* 操作结果:依次对L的每个数据元素输出 */
Status visit(ElemType c)
{
	printf("%d ", c);
	return OK;
}

void ListTraverse(LinkList L)
{
	LinkList p = L->next;
	while (p)
	{
		visit(p->data);
		p = p->next;
	}
	printf("\n");
	return OK;
}

/* 初始条件:链式线性表L已存在。操作结果:将L重置为空表 */
Status ListClear(LinkList* L)
{
	LinkList p, q;
	//指针p指向第一个结点
	p = (*L)->next;

	while (p)
	{
		q = p->next;  //指针q指向 p指向结点的 后一个结点(把p指向结点 后一个结点的地址赋值给q)
		free(p);   //释放 p指向的结点
		p = q;     //让指针p指向(新的)第一个结点
	}

	(*L)->next = NULL;   //头结点的指针域置为空
	return OK;
}

/*  随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
void CreateList_Tail(LinkList* L, int n)
{
	LinkList p, r;
	srand(time(0));   //初始化随机种子
	(*L) = (LinkList)malloc(sizeof(Node));   //创建头结点
	r = (*L);    //指针r 指向链表尾部的结点

	for (int i = 0; i < n; i++)
	{
		p = (Node*)malloc(sizeof(Node));  //创建新结点,让p指向新结点
		p->data = rand() % 100 + 1;

		r->next = p;   //把新结点的地址 赋值给 表尾结点的指针域 
		r = p;        //让r指向新的表尾结点
	}

	r->next = NULL;
}


/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(LinkList* L, int i, ElemType e)
{
	LinkList p, s;
	p = (*L);    //p指向头结点
	int j = 1;
	while (p && j < i)
	{
		p = p->next;
		j++;
	}
	if (!p || j > i)   //满足p为空 或 j>i 其中一个条件就进入循环
	{
		return ERROR;
	}

	s = (LinkList)malloc(sizeof(Node));
	s->data = e;
	s->next = p->next;    //把p的后继结点的地址 赋值给 s的指针域
	p->next = s;    //再把s的地址 赋值给 p的指针域

	return OK;
}


/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值 */
//按位查找
Status GetElem(LinkList L, int i, ElemType* e)
{
	LinkList p;
	p = L->next;
	int j = 1;
	while (p && j < i)
	{
		p = p->next;
		j++;
	}
	if (!p || j > i)
	{
		return ERROR;
	}
	*e = p->data;

	return OK;
}

/* 初始条件:链式线性表L已存在 */
/* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
Status LocateElem(LinkList L, ElemType e)
{
	LinkList p = L->next;  //p指向头结点的后继结点(第一个结点)
	int i = 1;
	while (p)
	{
		if (p->data == e)
		{
			return i;
		}
		else
		{
			p = p->next;
			i++;
		}
	}

	return 0;
}

/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(LinkList* L, int i, ElemType* e)
{
	LinkList p, q;
	p = (*L);  // p指向头结点
	int j = 1;
	while (p->next && j < i)
	{
		p = p->next;
		j++;
	}
	if (!(p->next) || j > i)
	{
		return ERROR;
	}
	q = p->next;
	p->next = q->next;
	*e = q->data;
	free(q);

	return OK;
}

void test01()
{
	//1.线性单链表的整表创建(头插法)测试:
	LinkList La;
	CreateList_Head(&La, 10);  //参数以地址传入,指针接收
	//表长
	int i_length = 0;
	i_length = ListLength(La);
	printf("La的表长为:%d\n", i_length);   //La的表长为:10
	//判空
	Status i_empty;
	i_empty = ListEmpty(La);
	printf("表La是否为空(1为是/0为否):%d\n", i_empty);  //表La是否为空(1为是/0为否):0
	//遍历
	ListTraverse(La);  //37 81 45 81 59 36 78 59 86 79

	printf("----------------------------------------------\n");

	//2.清空表
	ListClear(&La);
	//表长
	i_length = ListLength(La);
	printf("La的表长为:%d\n", i_length);   //La的表长为:0
	//判空
	i_empty = ListEmpty(La);
	printf("表La是否为空(1为是/0为否):%d\n", i_empty);  //表La是否为空(1为是/0为否):1

	printf("----------------------------------------------\n");

	//3.线性单链表的整表创建(尾插法)测试:
	CreateList_Tail(&La, 5);
	//表长
	i_length = ListLength(La);
	printf("La的表长为:%d\n", i_length);   //La的表长为:5
	//判空
	i_empty = ListEmpty(La);
	printf("表La是否为空(1为是/0为否):%d\n", i_empty);  //表La是否为空(1为是/0为否):0
	//遍历
	ListTraverse(La);  //65 26 59 17 11
}

void test02()
{
	LinkList Lb;
	//初始化
	InitList(&Lb);
	//在Lb表头循环插入10个元素
	for (int i = 0; i < 10; i++)
	{
		ListInsert(&Lb, 1, i);
	}
	ListTraverse(Lb);   //9 8 7 6 5 4 3 2 1 0

	//按位查找
	//int i = 5;
	//ElemType e = 0;
	//GetElem(Lb, i, &e);
	//printf("表Lb的第 %d 个元素是 %d \n", i, e);   //表Lb的第 5 个元素是 5


	//按值查找
	//ElemType e = 11;
	//int i = LocateElem(Lb, e);
	//printf("表中值为 %d 的元素在第%d个位置(0表示不存在该元素)\n", e, i);

	//按位删除
	int i = 1;
	ElemType e;
	ListDelete(&Lb, i, &e);
	printf("Lb表中被删除的第 %d 个元素为 %d \n", i, e);   //Lb表中被删除的第 1 个元素为 9
	ListTraverse(Lb);    //8 7 6 5 4 3 2 1 0
	int j = ListLength(Lb);
	printf("表长为:%d\n", j);   //表长为:9
}

int main()
{
	//test01();

	test02();

	system("pause");
	return 0;
}

2.双链表( Double Linked List)

        单链表结点中只有一个指向其后继的指针,使得单链表只能从头结点依次顺序地向后遍历。要访问某个结点的前驱结点,只能从头开始遍历,访问后继结点的时间复杂度为O(1),访问前驱结点的时间复杂度为O(n).

        为了解决上述单链表的缺点,引入了 双链表,双链表结点中有两个指针prior 和 next,分别指向其前驱结点和后继结点。

如图

        双链表中结点类型的描述如下:

typedef struct DNode
{
	ElemType data;
	struct DNode* prior;
	struct DNode* next;
}DNode,* DLinkList;

   2.1 基本操作

        tips:双链表中的按值查找和按位查找的操作与单链表的相同。但双链表在插入和删除操作的实现上,与单链表有着较大的不同!

        

//双向链表
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

typedef int Status;
typedef int ElemType;

typedef struct DNode
{
	ElemType data;
	struct DNode* prior;
	struct DNode* next;
}DNode,* DLinkList;
//typedef struct DNode* DLinkList;

2.1.1 整表创建(尾插法)

/*  随机产生n个元素的值,建立带表头结点的双链表DL(尾插法) */
void CreateList_Tail(DLinkList* DL, int n)
{
	//srand(time(0));   //初始化随机种子
	//创建一个带头结点的单链表
	(*DL) = (DLinkList)malloc(sizeof(DNode));
	(*DL)->prior = NULL;
	(*DL)->next = NULL;

	//在头结点后,循环插入n个随机数
	DLinkList s;
	DLinkList p;
	p = (*DL);   //指针p指向头结点
	for (int i = 0; i < n; i++)
	{
		//创建新的结点
		s = (DLinkList)malloc(sizeof(DNode));
		//s->data = rand() % 100 + 1;  //随机生成100以内的数字
		s->data = i;

		//
		s->prior = p;
		s->next = p->next;
		p->next = s;

		p = s;   //指针向后移动
		
	}
}

2.1.2 求表长

//求表长
/* 初始条件:双链表DL已存在。操作结果:返回DL中数据元素个数 */
int ListLength(DLinkList DL)
{
	DLinkList p = DL->next;
	int i = 0;
	while (p)  //若p不为空
	{
		p = p->next;     
		i++;
	}

	//若为空表
	return i;
}

2.1.3 判空

//判空
/* 初始条件:双链表 DL已存在。操作结果:若 DL为空表,则返回TRUE,否则返回FALSE */
Status ListEmpty(DLinkList DL)
{
	if (DL->next)
	{
		return FALSE;
	}
	else
	{
		return TRUE;
	}
}

2.1.4 遍历

/* 初始条件:双链表DL已存在 */
/* 操作结果:依次对DL的每个数据元素输出 */
Status visit(ElemType c)
{
	printf("%d ", c);
	return OK;
}

void ListTraverse(DLinkList DL)
{
	DLinkList p = DL->next;
	while (p)
	{
		visit(p->data);
		p = p->next;
	}
	printf("\n");

}

测试代码:

2.1.5 清空 

/* 初始条件:双链表DL已存在。操作结果:将DL重置为空表 */
Status ListClear(DLinkList* L)
{
	DLinkList p, q;
	//指针p指向第一个结点
	p = (*L)->next;

	while (p)
	{
		q = p->next;  //指针q指向 p指向结点的 后一个结点(把p指向结点 后一个结点的地址赋值给q)
		free(p);   //释放 p指向的结点
		p = q;     //让指针p指向(新的)第一个结点
	}

	(*L)->next = NULL;   //头结点的指针域置为空
	return OK;
}

测试代码:

 2.1.6 初始化表

//初始化双链表
Status ListInit(DLinkList* DL)
{
	(*DL) = (DLinkList)malloc(sizeof(DNode));
	if (!(*DL))
	{
		return ERROR;
	}
	//头结点的前后指针域置空
	(*DL)->prior = NULL;
	(*DL)->next = NULL;

	return OK;
}

测试代码:

 

2.1.7  按位插入元素

/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(DLinkList* DL, int i, ElemType e)
{
	DLinkList p, s;
	p = (*DL);    //p指向头结点
	int j = 1;
	while (p && j < i)
	{
		p = p->next;
		j++;
	}
	if (!p || j > i)   //满足p为空 或 j>i 其中一个条件就进入循环
	{
		return ERROR;
	}

	s = (DLinkList)malloc(sizeof(DNode));
	s->data = e;

	s->prior = p;
	s->next = p->next;
	p->next = s;

	p = s;   //指针向后移动

	return OK;
}

测试代码:

 2.1.8 按位查找

//按位查找
Status GetElem(DLinkList DL, int i, ElemType* e)
{
	DLinkList p;
	p = DL->next;
	int j = 1;
	while (p && j < i)
	{
		p = p->next;
		j++;
	}
	if (!p || j > i)
	{
		return ERROR;
	}
	*e = p->data;

	return OK;
}

测试代码:

 

2.1.9 按值查找

//按值查找
Status LocateElem(DLinkList L, ElemType e)
{
	DLinkList p = L->next;  //p指向头结点的后继结点(第一个结点)
	int i = 1;
	while (p)
	{
		if (p->data == e)
		{
			return i;
		}
		else
		{
			p = p->next;
			i++;
		}
	}

	return 0;
}

测试代码:

 2.1.10 按位删除

//删除
Status ListDelete(DLinkList* L, int i, ElemType* e)
{
	DLinkList p,q;
	p = (*L);  // p指向头结点
	int j = 1;
	while (p->next && j < i)
	{
		p = p->next;
		j++;
	}
	if (!(p->next) || j > i)
	{
		return ERROR;
	}

	q = p->next;
	p->next = q->next;
	p->next->prior = q->prior;
	*e = q->data;

	free(q);

	return OK;
}

测试代码:

2.2 双链表实现完整代码

#define _CRT_SECURE_NO_WARNINGS 1


//双向链表
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

typedef int Status;
typedef int ElemType;

typedef struct DNode
{
	ElemType data;
	struct DNode* prior;
	struct DNode* next;
}DNode,* DLinkList;
//typedef struct DNode* DLinkList;


//初始化双链表
Status ListInit(DLinkList* DL)
{
	(*DL) = (DLinkList)malloc(sizeof(DNode));
	if (!(*DL))
	{
		return ERROR;
	}
	//头结点的前后指针域置空
	(*DL)->prior = NULL;
	(*DL)->next = NULL;

	return OK;
}

//判空
/* 初始条件:双链表 DL已存在。操作结果:若 DL为空表,则返回TRUE,否则返回FALSE */
Status ListEmpty(DLinkList DL)
{
	if (DL->next)
	{
		return FALSE;
	}
	else
	{
		return TRUE;
	}
}

//求表长
/* 初始条件:双链表DL已存在。操作结果:返回DL中数据元素个数 */
int ListLength(DLinkList DL)
{
	DLinkList p = DL->next;
	int i = 0;
	while (p)  //若p不为空
	{
		p = p->next;     
		i++;
	}

	//若为空表
	return i;
}

/*  随机产生n个元素的值,建立带表头结点的双链表DL(尾插法) */
void CreateList_Tail(DLinkList* DL, int n)
{
	//srand(time(0));   //初始化随机种子
	//创建一个带头结点的单链表
	(*DL) = (DLinkList)malloc(sizeof(DNode));
	(*DL)->prior = NULL;
	(*DL)->next = NULL;

	//在头结点后,循环插入n个随机数
	DLinkList s;
	DLinkList p;
	p = (*DL);   //指针p指向头结点
	for (int i = 0; i < n; i++)
	{
		//创建新的结点
		s = (DLinkList)malloc(sizeof(DNode));
		//s->data = rand() % 100 + 1;  //随机生成100以内的数字
		s->data = i;

		//
		s->prior = p;
		s->next = p->next;
		p->next = s;

		p = s;   //指针向后移动
		
	}
}

/* 初始条件:双链表DL已存在 */
/* 操作结果:依次对DL的每个数据元素输出 */
Status visit(ElemType c)
{
	printf("%d ", c);
	return OK;
}

void ListTraverse(DLinkList DL)
{
	DLinkList p = DL->next;
	while (p)
	{
		visit(p->data);
		p = p->next;
	}
	printf("\n");

}

/* 初始条件:双链表DL已存在。操作结果:将DL重置为空表 */
Status ListClear(DLinkList* L)
{
	DLinkList p, q;
	//指针p指向第一个结点
	p = (*L)->next;

	while (p)
	{
		q = p->next;  //指针q指向 p指向结点的 后一个结点(把p指向结点 后一个结点的地址赋值给q)
		free(p);   //释放 p指向的结点
		p = q;     //让指针p指向(新的)第一个结点
	}

	(*L)->next = NULL;   //头结点的指针域置为空
	return OK;
}

/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(DLinkList* DL, int i, ElemType e)
{
	DLinkList p, s;
	p = (*DL);    //p指向头结点
	int j = 1;
	while (p && j < i)
	{
		p = p->next;
		j++;
	}
	if (!p || j > i)   //满足p为空 或 j>i 其中一个条件就进入循环
	{
		return ERROR;
	}

	s = (DLinkList)malloc(sizeof(DNode));
	s->data = e;

	s->prior = p;
	s->next = p->next;
	p->next = s;

	p = s;   //指针向后移动

	return OK;
}

//按位查找
Status GetElem(DLinkList DL, int i, ElemType* e)
{
	DLinkList p;
	p = DL->next;
	int j = 1;
	while (p && j < i)
	{
		p = p->next;
		j++;
	}
	if (!p || j > i)
	{
		return ERROR;
	}
	*e = p->data;

	return OK;
}


//按值查找
Status LocateElem(DLinkList L, ElemType e)
{
	DLinkList p = L->next;  //p指向头结点的后继结点(第一个结点)
	int i = 1;
	while (p)
	{
		if (p->data == e)
		{
			return i;
		}
		else
		{
			p = p->next;
			i++;
		}
	}

	return 0;
}

//删除
Status ListDelete(DLinkList* L, int i, ElemType* e)
{
	DLinkList p,q;
	p = (*L);  // p指向头结点
	int j = 1;
	while (p->next && j < i)
	{
		p = p->next;
		j++;
	}
	if (!(p->next) || j > i)
	{
		return ERROR;
	}

	q = p->next;
	p->next = q->next;
	p->next->prior = q->prior;
	*e = q->data;

	free(q);

	return OK;
}


void test01()
{

	//初始化表
	DLinkList DL;
	Status i_init = ListInit(&DL);
	printf("%d\n", i_init);    //1
	//求表长
	int i_length = ListLength(DL);
	printf("DL的长度为:%d\n", i_length);    //DL的长度为:0
	//判空
	Status i_empty = ListEmpty(DL);
	printf("DL是否为空(1为是/0为否):%d\n", i_empty);   //	DL是否为空(1为是 / 0为否):1

	printf("--------------------------------------------\n");
	//在表头循环插入0~9
	for (int i = 0; i < 10; i++)
	{
		ListInsert(&DL, 1, i);
	}
	//求表长
	i_length = ListLength(DL);
	printf("DL的长度为:%d\n", i_length);  //DL的长度为:10
	//判空
	i_empty = ListEmpty(DL);
	printf("DL是否为空(1为是/0为否):%d\n", i_empty);  //DL是否为空(1为是 / 0为否):0
	//遍历
	ListTraverse(DL);   //9 8 7 6 5 4 3 2 1 0


	按位查找
	//int i = 1;
	//ElemType e = 0;
	//GetElem(DL, i, &e);
	//printf("DL表中第 %d 个元素是 %d \n", i, e);   //DL表中第 1 个元素是 9

	//按值查找
	//ElemType e = 9;
	//int i = LocateElem(DL, e);
	//printf("表中值为 %d 的元素在第%d个位置(0表示不存在该元素)\n", e, i);  //表中值为 9 的元素在第1个位置(0表示不存在该元素)

	printf("--------------------------------------------\n");

	//按位删除
	int i = 1;
	ElemType e;
	ListDelete(&DL, i, &e);
	printf("DL表中被删除的第 %d 个元素为 %d \n", i, e);   //DL表中被删除的第 1 个元素为 9
	ListTraverse(DL);    //8 7 6 5 4 3 2 1 0
	int j = ListLength(DL);
	printf("表长为:%d\n", j);   //表长为:9

}

void test02()
{	
	DLinkList DL;
	CreateList_Tail(&DL, 10);
	//求表长
	int i_length = ListLength(DL);
	printf("DL的长度为:%d\n", i_length);      //DL的长度为:10
	//判空
	Status i_empty = ListEmpty(DL);		
	printf("DL是否为空(1为是/0为否):%d\n", i_empty);  //DL是否为空(1为是 / 0为否):0	
	//遍历
	ListTraverse(DL);  //0 1 2 3 4 5 6 7 8 9

	
	printf("----------------------------------\n");

	//清空
	ListClear(&DL);
	//求表长
	i_length = ListLength(DL);
	printf("DL的长度为:%d\n", i_length);
	//判空
	i_empty = ListEmpty(DL);
	printf("DL是否为空(1为是/0为否):%d\n", i_empty);
	ListTraverse(DL); //(空)

	printf("----------------------------------\n");
	
}




int main()
{
	//test01();

	test02();


	
	system("pause");
	return 0;
}

  • 12
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值