链表ADT实现

链表的定义:

链表链表有一系列不必再内存中连续的结构组成,不需要使用地址连续的存储单元。它是通过“链”来建立逻辑关系的,因此在对链表进行插入,删除操作时不需要移动元素,而只需要修改指针即可。

链表分类:按是否包含指向前继的指针可分为单链表和双向链表;按是否成环状可以分为循环链表和非循环链表。

由于连表示离散的分布在存储空间的,因此链表是非随机存取的,只能从某个特定节点开始遍历一次查找。

通常为方便操作,在链表第一个节点前附加一个头节点,头节点的指针与指向链表的第一个元素节点。

链表的实现与常见算法

单链表

  每个结构含有表元素和指向包含该元素后继的结构的指针。除了头节点,每一个结点都有唯一的前继。除最后一个结点,每一个结点都有一个后继。


插入:


删除:


双向链表

双向链表与单链表的不同之处在于,双向链表的每个结点含有两个指针域,其中一个指向直接前继,一个指向直接后继。这样双向链表可以沿两个方向进行遍历;

插入:

删除:


struct LNode {
	ElementType e;
	PtrToLNode Next;
};

typedef struct LNode *PtrToLNode;
typedef PtrToLNode List;
List List_Init(void)
{
	List L = (List)malloc(sizeof(LNode));
	L->Next = NULL;
	return L;
}

int List_IsEmpty(List L)
{
	if (L->Next = NULL)
		return 1;
	else
		return 0;
}

void List_Print(List L)
{
	PtrToLNode p = L->Next;
	while (p){
		printf("%d\t", p->e);
		p = p->Next;
	}
	printf("\n");
}

void List_Pre_Create(List L)//头插法建立单链表
{
	ElementType x;
	scanf("%d", &x);
	while (x != 9999) {
		PtrToLNode p = (PtrToLNode)malloc(sizeof(LNode));
		p->e = x;
		p->Next = L->Next;
		L->Next = p;
		scanf("%d", &x);
	}
}

void List_Post_Create(List L)//尾差法建立单链表
{
	ElementType x;
	PtrToLNode p, r = L;
	scanf("%d", &x);
	while (x != 9999) {
		p = (PtrToLNode)malloc(sizeof(LNode));
		p->e = x;
		r->Next = p;
		r = p;
		scanf("%d", &x);
	}
	r->Next = NULL;
}

PtrToLNode List_FindPre(List L, PtrToLNode r)//返回结点r的直接前继
{
	PtrToLNode pre = L, p = pre->Next;
	while (p != r) {
		pre = p;
		p = p->Next;
	}
	return pre;
}

int List_Length(List L)//求链表长度
{
	int Length = 0;
	PtrToLNode p = L->Next;
	while (p) {
		++Length;
		p = p->Next;
	}
	return Length;
}

void List_Insert(List L, Position p, ElementType x)//在结点p处插入新节点
{
	PtrToLNode pre = List_FindPre(L, p), s;
	s = (PtrToLNode)malloc(sizeof(LNode));
	s->e = x;
	s->Next = p;
	pre->Next = s;
}

PtrToLNode List_FindMid(List L)//返回中间元素结点
{
	PtrToLNode p, r;
	p = r = L->Next;
	while (r->Next != NULL && r->Next->Next != NULL){
		p = p->Next;
		r = r->Next->Next;
	}
	printf("%d\n", p->e);
	return p;
}

void List_Delete(List L, ElementType x)//删除节点
{
	PtrToLNode pre = L, p = L->Next, temp;
	while (p){
		if (p->e != x) {
			pre = p;
			p = p->Next;
		}
		else{
			temp = p->Next;
			pre->Next = temp;
			free(p);
			p = temp;
		}
	}
}

void List_DeleteRepeat(List L)//删除有序链表中重复元素的结点
{
	PtrToLNode pre = L->Next, p = pre->Next, temp;
	while (p){
		if (pre->e == p->e) {
			temp = p->Next;
			pre->Next = temp;
			free(p);
			p = temp;
		}
		else {
			pre = p;
			p = p->Next;
		}
	}
}

PtrToLNode List_Last_K(List L, int k)//返回倒数第K个结点
{
	PtrToLNode p, r;
	p = r = L;
	if (k > List_Length(L)) {
		printf("The k is Bigger Than L's Length!\n");
		return NULL;
	}
	for (int i = 0; i < k; ++i)
		r = r->Next;
	while (r){
		r = r->Next;
		p = p->Next;
	}
	printf("%d\n", p->e);
	return p;
}
/*若两单链表有公共结点,则从起始公共结点至尾结点两者均相同,因此将两链表尾部对齐,开始比较第一个相同结点即为起始公共结点*/
PtrToLNode List_CommonNode(List L1, List L2)//返回两单链表的公共起始节点
{
	int Length1, Length2, dist;
	PtrToLNode longlist, shortlist;
	Length1 = List_Length(L1);
	Length2 = List_Length(L2);
	if (Length1 > Length2) {
		longlist = L1->Next;
		shortlist = L2->Next;
		dist = Length1 - Length2;
	}
	else {
		longlist = L2->Next;
		shortlist = L1->Next;
		dist = Length2 - Length1;
	}
	while (dist--)
		longlist = longlist->Next;
	while(longlist && longlist->e != shortlist->e){
		longlist = longlist->Next;
		shortlist = shortlist->Next;
	}
	PtrToLNode p = longlist;
	while (p) {
		printf("%d\n", p->e);
		p = p->Next;
	}
	return longlist;
}

void List_Reverse(List L)//
{
	PtrToLNode pre, p, r;
	pre = L;
	p = pre->Next;
	r = p->Next;
	p->Next = NULL;//将逆置后的p将成为尾结点,将其指针域置空
	while (r) {
		pre = p;
		p = r;
		r = r->Next;//遍历链表
		p->Next = pre;//逆置
	}
	L->Next = p;//p结点将成为你逆置后的第一个节点,将头节点指向该节点
}
</pre><pre name="code" class="cpp"><pre name="code" class="cpp">void List_Reverse1(List L)//利用头插法逆置链表
{
	PtrToLNode p, r;
	p = L->Next;
	L->Next = NULL;
	while (p) {
		r = p->Next;
		p->Next = L->Next;
		L->Next = p;
		p = r;
	}
}

 
List List_Reverse1(List L, int m, int n)//逆置第m个结点至第n个结点结点
{
	List prefirst, first, p, r;
	prefirst = L;
	first = p = L->Next;
	for (int i = 1; i != m; ++i) {
		prefirst = p;
		p = p->Next;
	}//prefirst指向第m-1个结点
	first = p;//first指向第m个结点
	for (int i = m; i <= n; ++i) {
		r = p->Next;
		p->Next = prefirst->Next;
		prefirst->Next = p;
		p = r;
	}//利用头插法将m至n结点逆置
	first->Next = p;//将first的指针域指向第n+1个结点
	return L;
}

双链表


已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页