数据结构3--带头节点的双向循环链表

//Common.h
#ifndef _COMMON_H_
#define _COMMON_H_

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <vld.h>
#include <malloc.h>
#include <assert.h>

typedef int ElemType;
#endif
//dclist.h
#ifndef _DCLIST_H_
#define _DCLIST_H_

#include "Common.h"
//带头节点的双向循环链表
//定义节点
typedef struct DCListNode{
	ElemType data;
	struct DCListNode* next;
	struct DCListNode* prev;
}DCListNode;

typedef DCListNode* DCList;

//声明
void DCListInit(DCList *phead);
void DCListPushBack(DCList *phead,ElemType x);
void DCListPopBack(DCList* phead);
void DCListPushFront(DCList* phead,ElemType x);
void DCListPopFront(DCList* phead);
void DCListShow(DCList phead);
size_t DCListLength(DCList phead);
ElemType DCListFront(DCList phead);
ElemType DCListBack(DCList phead);
void DCListInerstByVal(DCList phead, ElemType key);
void DCListEraseByVal(DCList phead, ElemType key);
DCListNode* DCListFind(DCList phead, ElemType key);
void DCListSort(DCList phead);
void DCListReverse(DCList phead);
void DCListEraseAll(DCList phead, ElemType key);
void DCListClear(DCList* phead);
void DCListDestory(DCList* phead);

/
//实现
DCListNode* _Buynode(ElemType v = ElemType())//初始化为0
{
	//申请头结点 和节点(自循环)
	//有了头结点就不用考虑头结点不存在的情况
	DCListNode* _S= (DCListNode*)malloc(sizeof(DCListNode));
	assert(_S != NULL);
	_S->data = v;
	_S->next = _S->prev = _S;
	return _S;

}
void DCListInit(DCList *phead)
{
	//疑问?为什么不用断言
	//让头指针指向头结点
	*phead = _Buynode();
}
void DCListPushBack(DCList *phead, ElemType x)
{
	assert(phead != NULL);
	//申请新的节点
	DCListNode* s = _Buynode(x);
	DCListNode* head = *phead;

	s->next = head;
	s->prev = head->prev;
	s->prev->next = s;
	head->prev = s;

}
void DCListPopBack(DCList* phead)
{
	assert(phead != NULL);
	DCListNode* head = *phead;//头结点
	//注意判空
	if (head->next == head)
	{
		return;
	}
	//先找到最后一个节点
	DCListNode* p = head->prev;
	p->prev->next = head;
	head->prev = p->prev;//p->next->prev 相当于 head->prev
	free(p);
}
void DCListPushFront(DCList* phead, ElemType x)
{
	assert(phead != NULL);
	DCListNode* head = *phead;
	//申请新的节点
	DCListNode* s = _Buynode(x);

	s->next = head->next;
	s->prev = head;
	s->prev->next = s;
	s->next->prev = s;
}
void DCListPopFront(DCList* phead)
{
	assert(phead != NULL);
	DCListNode* head = *phead;
	//判空
	if (head->next == head)
	{
		return;
	}
	DCListNode* s = head->next;

	head->next = s->next;//s->prev->next=s->next
	s->next->prev = head;
	free(s);
}
void DCListShow(DCList phead)
{
	assert(phead != NULL);
	DCListNode* head = phead->next;
	//注意这里的循环条件以及head
	while (head!= phead)
	{
		printf("%d->", head->data);
		head = head->next;
	}
	printf("Over!\n");
}
size_t DCListLength(DCList phead)
{
	assert(phead != NULL);
	DCListNode* head = phead->next;
	size_t size = 0;
	while (head != phead)
	{
		size++;
		head = head->next;
	}
	return size;
}
ElemType DCListFront(DCList phead)
{
	assert(phead != NULL);
	//判空 疑问这里的phead为什么不用加*
	/*if (phead->next == phead)
	{
		return;
	}*/
	assert(phead->next != NULL);
	return phead->next->data;
}
ElemType DCListBack(DCList phead)
{
	assert(phead != NULL);
	assert(phead->next != phead);
	return phead->prev->data;
}
void DCListInerstByVal(DCList phead, ElemType key)
{
	assert(phead != NULL);
	//构建节点
	DCListNode* s = _Buynode(key);
	//不能用find查找是因为find是查找相等的
	
	//或者自己进行查找,再进行插入
	DCListNode* head = phead->next;
	while (head != phead&&head->data<key)
	{
		head = head->next;
	}

	//符合所有情况
	s->next = head;
	s->prev = head->prev;
	s->next->prev = s;
	s->prev->next = s;

}
void DCListEraseByVal(DCList phead, ElemType key)
{
	assert(phead != NULL);
    //第一个结点
	DCListNode* head = phead->next;
	
		//查找
		DCListNode* p = DCListFind(phead, key);
		//没有找到和链表为空的情况find中都考虑了
		if (p == NULL)
		{
			return;
		}
		//删除
		p->next->prev = p->prev;
		p->prev->next = p->next;
		free(p);
	
}
DCListNode* DCListFind(DCList phead, ElemType key)
{
	assert(phead != NULL);
	DCListNode* s = phead->next;
	//考虑链表为空的时候的情况
	while (s != phead&&s->data !=key)
	{
		s = s->next;
	}
	
	//当其遍历一遍之后发现没有找到时,会回到头结点,此时和链表为空的情况一样
	if (s == phead)
	{
		return NULL;
	}
	return s;
}
//排序思路:先断开链接,节点是否链路完 向后走,寻找位置进行链路
void DCListSort(DCList phead)
{
	assert(phead != NULL);
	//只有一个节点时,不需要进行逆置
	if (DCListLength(phead) == 1)
	{
		return;
	}
	//断开连接 注意!!还是有两个指向没断开
	DCListNode* p = phead->next;;
	DCListNode* q = p->next;
	p->next = phead;
	phead->prev = p;
	//说明节点还没有链路完成
	while (q != phead)
	{
		p = q;
		q = q->next;
	//其它节点进行按值插入
		DCListNode* tmp = phead->next;
		
		//寻找位置 考虑有多个数据已经插入好了
		while (tmp != phead&&p->data >tmp->data)
		{
			tmp = tmp->next;//如果存在一个以上的节点,就得完后走寻找插入位置
		}
		p->next = tmp;
		p->prev = tmp->prev;
		p->next->prev = p;
		p->prev->next = p;
	}
}
void DCListReverse(DCList phead)
{
	assert(phead != NULL);
	//只有一个节点时,不需要进行逆置
	if (DCListLength(phead) == 1)
	{
		return;
	}
	//断开连接
	DCListNode* p = phead->next;;
	DCListNode* q = p->next;
	p->next = phead;
	phead->prev = p;

	//排除只有一个节点 疑问
	while (q != phead)
	{
		p = q;
		q = q->next;

		p->next = phead->next;
		p->prev = phead;
		p->next->prev = p;
		p->prev->next = p;

	}

	
}
void DCListEraseAll(DCList phead, ElemType key);

void DCListClear(DCList* phead)
{
	assert(phead != NULL);
	
	//找到第一个节点 然后一个一个释放
	DCListNode* head = (*phead)->next;
	//考虑没有节点以及已经遍历完一遍
	while (head != *phead)
	{
	    head->prev->next = head->next;
		head->next->prev = head->prev;
		free(head);
		head = (*phead)->next;//注意!!! 更新head 让其指向下一个
	}
}
void DCListDestory(DCList* phead)
{
	assert(phead != NULL);
	DCListClear(phead);
	free(*phead);
	*phead = NULL;//预防野指针
}


#endif
//mian.cpp
#include "dclist.h"

int main()
{
	DCList list;
	DCListInit(&list);
	system("pause");
	return 0;
}

 

上一篇:链表翻转


下一篇:两个链表有一个交点,如何在时间复杂度 O(n) 和 空间复杂度 O(1) 的条件下实现?_字节跳动面试题