双向循环链表

文章目录

      • 双向循环链表
        • 双向循环链表节点结构
      • 双向循环链表的操作
        • 双向循环链表的插入
          • 双向循环链表的末尾插入
          • 双向循环链表的有序插入
        • 双向循环链表节点删除
          • 根据```element```进行删除
          • 根据节点指针删除
        • 双向循环链表的清空
      • 演示与测试视频
      • 源代码

双向循环链表

  在单向循环链表中,如果要在末尾插入一个节点,必须从head一个节点一个节点往后查询,尽管新建节点是插入在末尾节点和起始节点之间。在节点数较多的情况下,这一过程是费时的。此外,在实际应用中,有时需要逆向访问表中元素,这对单向链表或单向循环链表结构来说显然是困难的。为解决这一问题,可将链表设计成双向链表或双向循环链表。
  以带表头节点的双向循环链表为例:
双向循环链表_第1张图片

双向循环链表节点结构

  可见,双向循环链表的每个节点包含三个域:elementprevnext。其中element域为元素域,prev为指向前驱节点的指针,next为指向后继节点的指针。
  双向循环链表的每个节点的结构都具有如下定义的结构类型(element域定义为int型数据):

struct _node
{
	int element;
	struct _node* prev;
	struct _node* next;
};
typedef struct _node node;

双向循环链表的操作

双向循环链表的插入

  双向循环链表的插入分末尾插入和数据有序插入来讨论。

双向循环链表的末尾插入

  在双向循环链表中,末尾插入不再需要从head开始一个节点一个节点往后查询,在表头节点中存有指向末尾节点的指针,可以直接将新建节点插在末尾节点和表头节点。

bool NodeInsertLast(node* head, node* n)
{
	ASSERT(head);
	ASSERT(n);

	head->element++;
	node* ptr = head->prev;

	n->next = ptr->next;
	ptr->next->prev = n;

	ptr->next = n;
	n->prev = ptr;
	return true;
}
双向循环链表的有序插入
bool NodeInsertOrder(node* head, node* n)
{
	ASSERT(head);
	ASSERT(n);

	head->element++;
	node* ptr = head->next;
	while (ptr != head)
	{
		if (ptr->element > n->element)
			break;
		ptr = ptr->next;
	}
	ptr->prev->next = n;
	n->prev = ptr->prev;

	n->next = ptr;
	ptr->prev = n;

	return true;
}

  可以看出,双向循环链表采用常规的有序插入办法,和单向循环链表的操作差别不大,主要是多了一个指针需要处理。

双向循环链表节点删除

  节点的删除,可以像单向循环链表那样,根据element进行查找,然后删除;在实际项目中,节点在插入链表之后,指向该节点的指针变量一般并不会改变,所以对该节点中存放的数据进行修改,或是删除该节点时,也可以直接通过该指针变量进行操作。

根据element进行删除
bool NodeDeleteForEle(node* head, int element)
{
	ASSERT(head);
	head->element--;
	node* ptr = head->next;
	while (ptr != head)
	{
		if (ptr->element == element)
		{
			ptr->prev->next = ptr->next;
			ptr->next->prev = ptr->prev;
			free(ptr);
			return true;
		}
		ptr = ptr->next;
	}
	return false;
}
根据节点指针删除
bool NodeDeleteForPtr(node* head, node* n)
{
	ASSERT(head);
	ASSERT(n);

	head->element--;
	n->prev->next = n->next;
	n->next->prev = n->prev;
	free(n);
	return true;
}

双向循环链表的清空

void ListClear(node* head)
{
	ASSERT(head);
	head->element = 0;
	node* ptr = head->next;
	node* freePtr = NULL;

	while (ptr != head)
	{
		ptr->prev->next = ptr->next;
		ptr->next->prev = ptr->prev;
		freePtr = ptr;
		ptr = ptr->next;
		free(freePtr);
	}
}

演示与测试视频

双向循环链表操作显示

源代码

#include 
#include 
#include 

#define ASSERT(x)																			\
do																							\
{																							\
	if (!x)																					\
	{																						\
		printf("%s assert false! function:%s, line:%d\r\n", #x, __FUNCTION__, __LINE__);	\
		while (1);																			\
	}																						\
} while (0);

struct _node
{
	int element;
	struct _node* prev;
	struct _node* next;
};
typedef struct _node node;

node* NodeCreate(int element)
{
	node* ptr = (node*)malloc(sizeof(struct _node));
	if (ptr == NULL)
	{
		return NULL;
	}
	ptr->element = element;
	ptr->next = ptr;
	ptr->prev = ptr;
	return ptr;
}


bool NodeInsertLast(node* head, node* n)
{
	ASSERT(head);
	ASSERT(n);

	head->element++;
	node* ptr = head->prev;

	n->next = ptr->next;
	ptr->next->prev = n;

	ptr->next = n;
	n->prev = ptr;
	return true;
}

bool NodeInsertOrder(node* head, node* n)
{
	ASSERT(head);
	ASSERT(n);

	head->element++;
	node* ptr = head->next;
	while (ptr != head)
	{
		if (ptr->element > n->element)
			break;
		ptr = ptr->next;
	}
	ptr->prev->next = n;
	n->prev = ptr->prev;

	n->next = ptr;
	ptr->prev = n;

	return true;
}

bool NodeDeleteForEle(node* head, int element)
{
	ASSERT(head);
	head->element--;
	node* ptr = head->next;
	while (ptr != head)
	{
		if (ptr->element == element)
		{
			ptr->prev->next = ptr->next;
			ptr->next->prev = ptr->prev;
			free(ptr);
			return true;
		}
		ptr = ptr->next;
	}
	return false;
}

bool NodeDeleteForPtr(node* head, node* n)
{
	ASSERT(head);
	ASSERT(n);

	head->element--;
	n->prev->next = n->next;
	n->next->prev = n->prev;
	free(n);
	return true;
}

void ListClear(node* head)
{
	ASSERT(head);
	head->element = 0;
	node* ptr = head->next;
	node* freePtr = NULL;

	while (ptr != head)
	{
		ptr->prev->next = ptr->next;
		ptr->next->prev = ptr->prev;
		freePtr = ptr;
		ptr = ptr->next;
		free(freePtr);
	}
}

/***************************************************************************/

#define LISTY	0
#define NODEY	10
#define COMMY	20
#define NODEW	18
#define LOCX(i)	((i)*NODEW-6)

node* nodeCreatePtr = NULL;

char* function[] =
{
	"NodeCreate",
	"NodeInsertLast",
	"NodeInsertOrder",
	"NodeDeleteForEle",
	"NodeDeleteForPtr",
	"ListClear"
};

void SetCursorPosition(int x, int y)
{
	COORD cursorPisition;
	cursorPisition.X = x;
	cursorPisition.Y = y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cursorPisition);
}

void ListPrintAtConsole(node* head)
{
	node* ptr = head;
	int nodeNum = 0;
	/********************************新建节点********************************/
	if (nodeCreatePtr != NULL)
	{
		SetCursorPosition(1, NODEY);
		printf("新建节点");
		SetCursorPosition(0, NODEY + 1);
		printf("----------");
		SetCursorPosition(0, NODEY + 2);
		printf("----------");
		SetCursorPosition(0, NODEY + 3);
		printf("|%08d|", nodeCreatePtr->element);
		SetCursorPosition(0, NODEY + 4);
		printf("----------");
		SetCursorPosition(0, NODEY + 5);
		printf("|%8d|", nodeCreatePtr);
		SetCursorPosition(0, NODEY + 6);
		printf("----------");
		SetCursorPosition(0, NODEY + 7);
		printf("|%8d|", nodeCreatePtr);
	}
	/********************************头 指 针********************************/
	SetCursorPosition(1, LISTY + 1);
	printf("Head");
	SetCursorPosition(0, LISTY + 2);
	printf("----------");
	SetCursorPosition(0, LISTY + 3);
	printf("|%8d|------->", head);
	SetCursorPosition(0, LISTY + 4);
	printf("----------");

	/********************************起始节点********************************/
	ptr = head;
	{
		SetCursorPosition(LOCX(++nodeNum), LISTY);
		printf("    --------------");
		SetCursorPosition(LOCX(nodeNum), LISTY + 1);
		printf("   |   %8d", ptr);
		SetCursorPosition(LOCX(nodeNum), LISTY + 2);
		printf("   |  ----------");
		SetCursorPosition(LOCX(nodeNum), LISTY + 3);
		printf("---|->|%8d|<-", ptr->element);
		SetCursorPosition(LOCX(nodeNum), LISTY + 4);
		printf("|  |  ----------");
		SetCursorPosition(LOCX(nodeNum), LISTY + 5);
		printf("|   --|%8d|", ptr->prev);
		SetCursorPosition(LOCX(nodeNum), LISTY + 6);
		printf("|     ----------");
		SetCursorPosition(LOCX(nodeNum), LISTY + 7);
		printf("|     |%8d|--", ptr->next);
		SetCursorPosition(LOCX(nodeNum), LISTY + 8);
		printf("|     ----------");
		SetCursorPosition(LOCX(nodeNum), LISTY + 9);
		printf(" ----------------- ");
	}
	/********************************中间节点********************************/
	ptr = ptr->next;
	while (ptr != head)
	{
		nodeNum++;
		SetCursorPosition(LOCX(nodeNum), LISTY);
		printf("------------------");
		SetCursorPosition(LOCX(nodeNum), LISTY + 1);
		printf("       %8d", ptr);
		SetCursorPosition(LOCX(nodeNum), LISTY + 2);
		printf("      ----------");
		SetCursorPosition(LOCX(nodeNum), LISTY + 3);
		printf("    ->|%8d|<-", ptr->element);
		SetCursorPosition(LOCX(nodeNum), LISTY + 4);
		printf("|  |  ----------");
		SetCursorPosition(LOCX(nodeNum), LISTY + 5);
		printf(" --|--|%8d|", ptr->prev);
		SetCursorPosition(LOCX(nodeNum), LISTY + 6);
		printf("   |  ----------");
		SetCursorPosition(LOCX(nodeNum), LISTY + 7);
		printf("---   |%8d|--", ptr->next);
		SetCursorPosition(LOCX(nodeNum), LISTY + 8);
		printf("      ----------");
		SetCursorPosition(LOCX(nodeNum), LISTY + 9);
		printf("-------------------");
		ptr = ptr->next;
	}
	SetCursorPosition(LOCX(nodeNum) + 18, LISTY + 1);
	printf("|");
	SetCursorPosition(LOCX(nodeNum) + 18, LISTY + 2);
	printf("|");
	SetCursorPosition(LOCX(nodeNum) + 18, LISTY + 8);
	printf("|");
}


char GetCommand(void)
{
	char command;
	SetCursorPosition(0, COMMY);
	printf("\r\n[T]:%s", function[0]);
	printf("\r\n[L]:%s", function[1]);
	printf("\r\n[O]:%s", function[2]);
	printf("\r\n[E]:%s", function[3]);
	printf("\r\n[P]:%s", function[4]);
	printf("\r\n[C]:%s", function[5]);
	printf("\r\n[Q]:Quit");
	printf("\r\n请选择要操作的命令并按回车: ");
	printf("\b");
	while (true)
	{
		while ((command = getchar()) == '\n');
		command = tolower(command);
		if (command == 't' || command == 'l' || command == 'o' || command == 'e' || command == 'p' || command == 'c' || command == 'q')
		{
			while (getchar() != '\n');
			return command;
		}
		printf("\r\n请输入有效命令或按获取帮助:");
	}
}

void DoCommand(char Command, node* head)
{
	int element = '\n';
	switch (Command)
	{
		case 't':
		{
					printf("请输入创建节点的element值并按回车: ");
					while (element == '\n')
						scanf_s("%d", &element);
					nodeCreatePtr = NodeCreate(element);
					break;
		}
		case 'l':
		{
					if (nodeCreatePtr != NULL)
					{
						NodeInsertLast(head, nodeCreatePtr);
					}
					nodeCreatePtr = NULL;
					break;
		}
		case 'o':
		{
					if (nodeCreatePtr != NULL)
					{
						NodeInsertOrder(head, nodeCreatePtr);
					}
					nodeCreatePtr = NULL;
					break;
		}
		case 'e':
		{
					printf("请输入删除节点的element值并按回车: ");
					while (element == '\n')
						scanf_s("%d", &element);
					NodeDeleteForEle(head, element);
					break;
		}
		case 'p':
		{
					printf("请输入删除节点的地址并按回车: ");
					while (element == '\n')
						scanf_s("%d", &element);
					NodeDeleteForPtr(head,(node*)element);
					break;
		}
		case 'c':
		{
					ListClear(head);
					break;
		}
		case 'q':
		{
					exit(0);
					break;
		}
	}
}

int main()
{

	node head = { 0, &head, &head };
	while (1)
	{
		system("cls");
		ListPrintAtConsole(&head);
		DoCommand(GetCommand(), &head);
	}
}

你可能感兴趣的:(数据结构)