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

目录

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、付费专栏及课程。

余额充值