双向循环链表,C语言实现

今天某家公司笔试题,遇到了一个双向循环链表。

调试后成功解决。文末附上完整程序。 

定义结点是如下结构:

struct node{
	int val;
	
	struct node * next;
	struct node * prev;
};

 next指针指向后一个结点,prev指向前一个结点

定义双向循环链表的结构如下

struct list{
	int len;
	NODE* head;
    NODE* tail;
};

head指针指向虚拟头节点,tail指向虚拟尾结点,这两个结点用于标识头尾。这样当初始化一个链表后,链表示意图如下:

a80a106a5b6f4474820e337390e5b983.png

排序算法用基础的冒泡排序,基础操作是链表结点n1和n2交换,这里我使用四个指针变量,简化了编程中可能的复杂逻辑思考, 这四个变量存储两个待交换结点的前一个和后一个结点,交换即使得这两个结点的前一个和后一个结点变成对应的节点,即n1结点的前一个和后一个结点变成n2对应的前一个和后一个结点;n2如是。这里注意特殊情况是,待交换n1和n2结点相邻。通过简化可使得程序精简,这里为了便于理解不做简化。交换程序如下:

void swap_element( NODE* n1 , NODE* n2 ){
	NODE* n1_prev = n1->prev, *n1_next = n1->next;
	NODE* n2_prev = n2->prev, *n2_next = n2->next;
	
	if (n1_next != n2 && n1_prev!= n2 ){
		//place n1 to n2
		n1->next = n2_next;
		n2_next->prev = n1;

		n1->prev = n2_prev;
		n2_prev->next = n1;

		//place n2 to n1
		n2->next = n1_next;
		n1_next->prev = n2;

		n2->prev = n1_prev;
		n1_prev->next = n2;

	}
	else{

		if (n1_next == n2){
			 n1_prev->next = n2;
			n2->prev = n1_prev;
			n2->next = n1;

			n1->prev = n2;
			n1->next = n2_next;

			n2_next->prev = n1;		
		}else{
			 n2_prev->next = n1;
			n1->prev = n2_prev;
			n1->next = n2;

			n2->prev = n1;
			n2->next = n1_next;

			n1_next->prev = n2;		
		}
	
	}
	return;
	
}

完整的程序如下:

#include<stdio.h>
#include<stdlib.h>

#define   OK   0
#define   ERR  -1
#define status int
struct node {
	int val;

	struct node* next;
	struct node* prev;
};

typedef struct node NODE;


struct list {
	int len;
	NODE* head;
	NODE* tail;
};

typedef struct list LIST;

//create list
status list_create(LIST* ptr_list) {

	//create virtual head node
	NODE* dummy_head = (NODE*)malloc(sizeof(NODE));
	//handle err
	if (dummy_head == NULL) {
		return ERR;
	}

	//create virtual tail node
	NODE* dummy_tail = (NODE*)malloc(sizeof(NODE));
	//handle err
	if (dummy_tail == NULL) {
		free(dummy_head);
		return ERR;
	}

	//assign to ptr_list

	ptr_list->len = 0;
	ptr_list->head = dummy_head;
	ptr_list->tail = dummy_tail;

	//make loop
	ptr_list->head->next = ptr_list->tail;
	ptr_list->tail->prev = ptr_list->head;


	ptr_list->head->prev = ptr_list->tail;
	ptr_list->tail->next = ptr_list->head;

	return OK;
}
//add to list
status list_insert(LIST* ptr_list, int val) {

	//create new node
	NODE* new_node = (NODE*)malloc(sizeof(NODE));
	//handle err
	if (new_node == NULL) {
		return ERR;
	}

	//assign val to new node

	new_node->val = val;

	//make loop
	new_node->next = ptr_list->head->next;
	ptr_list->head->next->prev = new_node;

	ptr_list->head->next = new_node;
	new_node->prev = ptr_list->head;

	//adding nums
	++ptr_list->len;

	return OK;
}

void swap_element(NODE* n1, NODE* n2) {
	NODE* n1_prev = n1->prev, * n1_next = n1->next;
	NODE* n2_prev = n2->prev, * n2_next = n2->next;

	if (n1_next != n2 && n1_prev != n2) {
		//place n1 to n2
		n1->next = n2_next;
		n2_next->prev = n1;

		n1->prev = n2_prev;
		n2_prev->next = n1;

		//place n2 to n1
		n2->next = n1_next;
		n1_next->prev = n2;

		n2->prev = n1_prev;
		n1_prev->next = n2;

	}
	else {

		if (n1_next == n2) {
			n1_prev->next = n2;
			n2->prev = n1_prev;
			n2->next = n1;

			n1->prev = n2;
			n1->next = n2_next;

			n2_next->prev = n1;
		}
		else {
			n2_prev->next = n1;
			n1->prev = n2_prev;
			n1->next = n2;

			n2->prev = n1;
			n2->next = n1_next;

			n1_next->prev = n2;
		}

	}
	return;

}

//sort list
status list_sort(LIST* ptr_list) {

	if (ptr_list->head->next == ptr_list->tail || ptr_list->len == 1) {
		return OK;   //null list or just one element;
	}

	//bubble sort
	for (NODE* j = ptr_list->tail->prev, *E = ptr_list->head; j->prev != E; j = j->prev)
		for (NODE* i = ptr_list->head->next; i != j; i = i->next)
			if (i->val > i->next->val)
			{
				if (i->next == j) {
					j = i;
				}

				swap_element(i, i->next);
				i = i->prev;

			}

	return OK;


}

//show list
void show_list(LIST* ptr_list) {

	if (ptr_list->head->next == ptr_list->tail) {
		printf(" empty list ! \n");
		return;
	}

	for (NODE* i = ptr_list->head->next; i != ptr_list->tail; i = i->next)
		printf(" %d", i->val);

	printf("\n");
	return;
}

int main() {

	LIST test;

	if (list_create(&test) == ERR) {
		printf("crated failed\n");
		return -1;
	}
	printf("list:");
	show_list(&test);
	list_insert(&test, -2);
	list_insert(&test, 0);
	list_insert(&test, 2);
	list_insert(&test, 3);
	list_insert(&test, 1);
	list_insert(&test, 2);
	list_insert(&test, 1);
	list_insert(&test, 3);

	printf("list:");
	show_list(&test);

	printf("sort list:\n");
	list_sort(&test);
	//swap_element(test.tail->prev , test.tail->prev->prev);
	printf("list:");
	show_list(&test);

	return 0;

}

运行效果如下:

 

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
循环双向链表是一种链表结构,它可以在单链表的基础上,增加一个指向前一个结点的指针,从而实现双向遍历。循环双向链表是指尾结点的 next 指针指向头结点,头结点的 prev 指针指向尾结点,形成一个循环。 以下是循环双向链表的 C 语言实现: ```c #include <stdio.h> #include <stdlib.h> typedef struct Node { int data; struct Node *prev; struct Node *next; } Node; Node *create_node(int data) { Node *new_node = (Node *)malloc(sizeof(Node)); new_node->data = data; new_node->prev = NULL; new_node->next = NULL; return new_node; } void insert_node(Node **head, Node *new_node) { if (*head == NULL) { *head = new_node; (*head)->prev = new_node; (*head)->next = new_node; } else { Node *tail = (*head)->prev; tail->next = new_node; new_node->prev = tail; new_node->next = *head; (*head)->prev = new_node; } } void delete_node(Node **head, Node *del_node) { if (*head == NULL || del_node == NULL) { return; } if (*head == del_node) { *head = del_node->next; } if (del_node->next != NULL) { del_node->next->prev = del_node->prev; } if (del_node->prev != NULL) { del_node->prev->next = del_node->next; } free(del_node); } void print_list(Node *head) { if (head == NULL) { printf("List is empty\n"); } else { Node *current = head; do { printf("%d ", current->data); current = current->next; } while (current != head); printf("\n"); } } int main() { Node *head = NULL; Node *node1 = create_node(1); Node *node2 = create_node(2); Node *node3 = create_node(3); insert_node(&head, node1); insert_node(&head, node2); insert_node(&head, node3); print_list(head); delete_node(&head, node2); print_list(head); return 0; } ``` 在上面的代码中,我们定义了一个 Node 结构体,表示循环双向链表的结点。create_node 函数用于创建一个新结点,insert_node 函数用于将新结点插入链表,delete_node 函数用于删除指定结点,print_list 函数用于打印链表。 在 main 函数中,我们创建了三个结点,然后插入链表,打印链表,删除第二个结点,再次打印链表

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值