데이터 구조 C 코드 2.3: 이중 연결 목록

요약 및 반성: 

1. 장점: 단일 연결 리스트와 비교하여 이중 연결 리스트는 역방향 순회 기능을 제공하며 각 노드는 연동

2. 단점: 단일 연결 목록에 비해 연산이 더 많고 *previous가 이전 노드를 가리켜야 하므로 구조도 이전 노드에 대한 포인터를 가지므로 더 많은 공간을 차지합니다.

3. 내 제안은 단일 연결 목록이면 충분하다는 것입니다.

학습 목표:

이중 연결 목록을 배우십시오 주요 목적은 연결 목록의 변형을 연습하고 더 많은 디자인 감각을 찾는 것이므로 실제 문제에 직면했을 때 일정한 모델링 능력을 갖게 될 것입니다.

학습 가이드: Fanshen의 코드

학습 작업:

  1. 코드를 복사합니다.
  2. insertElement와 같은 기능에 대해 추가 테스트를 수행합니다.
  3. locateElement 함수를 직접 구현하십시오.
  4. 버그를 선택하고 Fanshen Code에 메시지를 남겨주세요.
  5. CSDN 블로그 작성 도구로 그리거나 사진을 찍을 수 있는 손으로 그린 ​​아이콘이 있어야 합니다.
  6. 학습 결과 카탈로그

     1 스크라이브 코드

    1.1 이중 연결 리스트 구조

    1.2 연결 리스트 초기화

     1.3 연결된 목록 인쇄

    1.4 노드 삽입

    1.5 삭제 노드

    2. 노드 포지셔닝

    3. 단위 테스트

    3.1 추가 및 삭제

    3.2 포지셔닝

    3.3 주소 할당

    3.4 실행 결과

    4 모든 코드

3. 코드 설명

  1. 인쇄, 삽입, 위치 지정 및 삭제를 구현했습니다.
  2. 관련된 모든 포인터를 변경해야 하고 프로그램을 작성하는 데 도움이 되도록 그림을 그려야 합니다.
  3. 꼬리 노드를 제거할 때 주의해야 하며 경계 테스트가 필요합니다.

공부 시간:

2022.5.3

 1 스크라이브 코드

1.1 이중 연결 리스트 구조

/**
 * 双链表结构体,存储字符串数据
 */
typedef struct DoubleLinkeNdode {
	char data;
	struct DoubleLinkeNdode *previous;
	struct DoubleLinkeNdode *next;
} DLNode, *DLNodePtr;

1.2 연결 리스트 초기화

/**
 * @brief 初始化链表,创建一个头节点
 *
 * @return 返回头节点
 */
DLNodePtr initLinkList() {
	//申请空间
	DLNodePtr tempHeader = (DLNodePtr)malloc(sizeof(struct DoubleLinkeNdode) * 1);
	//初始化
	tempHeader->data = '\0';
	tempHeader->previous = NULL;
	tempHeader->next = NULL;
	return tempHeader;
}

 1.3 연결된 목록 인쇄

/**
 * @brief 打印链表
 *
 * @param paraHeader 传入头节点
 */
void printList(DLNodePtr paraHeader) {
	DLNodePtr p = paraHeader->next;
	//节点不为空,则打印数据
	while (p != NULL) {
		printf("%c", p->data);
		p = p->next;
	}
	printf("\n");
}

1.4 노드 삽입

/**
 * @brief 插入一个节点操作
 *
 * @param paraChar
 * @param paraHeader
 * @param paraPosition
 */
void insertElement(DLNodePtr paraHeader, char paraChar, int paraPosition) {
	//创建三个结构体变量:p查找查找插入链表位置,q申请新空间,r插入节点的后一节点,辅助插入
	DLNodePtr p, q, r;
	//1查找插入链表位置
	p = paraHeader;
	for (int i = 0; i < paraPosition; i++) {
		p = p->next;
		if (p == NULL) {
			printf("位置%d已经超出链表范围\n", paraPosition);
			return;
		}
	}

	//2申请空间
	q = (DLNodePtr)malloc(sizeof(struct DoubleLinkeNdode) * 1);
	//赋值
	q->data = paraChar;

	//3把新节点插入双链表
	r = p->next;
	q->next = p->next;
	q->previous = p;
	p->next = q;
	//如果不是尾节点,才需要把插入节点的后一节点指向插入节点(非常巧妙)
	if (r != NULL) {
		r->previous = q;
	}
	printf("插入元素%c成功!\n", paraChar);
}

1.5 삭제 노드

/**
 * @brief 删除一个节点操作
 * 
 * @param paraChar 
 * @param paraHeader 
 */
void deleteElement(DLNodePtr paraHeader, char paraChar) {
	//创建三个结构体变量:p为查找传入数据的前节点
	DLNodePtr p, q, r;
	//1查找传入数据的前节点
	p = paraHeader;
	while ((p->next != NULL) && (p->next->data != paraChar)) {
		p = p->next;
	}
	//2找不到数据,提示并结束
	if (p->next == NULL) {
		printf("节点%c不存在\n", paraChar);
		return;
	}
	//3找到数据,删除并提示
	q = p->next;
	r = q->next;
	p->next = r;
	if (r != NULL) {
		r->previous = p;
	}
	printf("你已经删除了节点%c", q->data);
	free(q);

}

2. 노드 포지셔닝

/**
 * @brief 定位节点
 * 
 * @param paraChar 
 * @param paraHeader 
 * 
 * @return 
 */
int locateElement(DLNodePtr paraHeader, char paraChar) {
	DLNodePtr p = paraHeader;
	for (int i = 0; p != NULL; i++) {
		if (p->data == paraChar) return i;
		p = p->next;
	}
	return -1;
}

3. 단위 테스트

3.1 추가 및 삭제

/**
 * 单元测试
 */
void insertDeleteTest() {
	printf("----insertDeleteTest开始测试-----\n");
	DLNodePtr tempList = initLinkList();
	printList(tempList);

	insertElement(tempList, 'H', 0);
	insertElement(tempList, 'e', 1);
	insertElement(tempList, 'l', 2);
	insertElement(tempList, 'l', 3);
	insertElement(tempList, 'o', 4);
	insertElement(tempList, '!', 5);
	printList(tempList);

	deleteElement(tempList, 'e');
	deleteElement(tempList, 'a');
	deleteElement(tempList, 'o');
	printList(tempList);

	insertElement(tempList, 'o', 1);
	printList(tempList);
	printf("--------------**********-------------\n\n");

}

3.2 포지셔닝

/**
 * 单元测试2
 */
void insertLocateTest() {
	printf("----insertLocateTest开始测试-----\n");
	int location, data;
	DLNodePtr tempList = initLinkList();
	printList(tempList);

	insertElement(tempList, 'H', 0);
	insertElement(tempList, 'e', 1);
	insertElement(tempList, 'l', 2);
	insertElement(tempList, 'l', 3);
	insertElement(tempList, 'o', 4);
	insertElement(tempList, '!', 5);
	printList(tempList);

	data = 'e';
	location = locateElement(tempList, data);
	if (location == -1) {
		printf("找不到元素%c!!!\n", data);
	} else {
		printf("元素%c的位置是%d\n", data, location);
	}
	data = 'a';
	location = locateElement(tempList, data);
	if (location == -1) {
		printf("找不到元素%c!!!\n", data);
	} else {
		printf("元素%c的位置是%d\n", data, location);
	}
	data = 'o';
	location = locateElement(tempList, data);
	if (location == -1) {
		printf("找不到元素%c!!!\n", data);
	} else {
		printf("元素%c的位置是%d\n", data, location);
	}
	printList(tempList);

	insertElement(tempList, 'o', 1);
	printList(tempList);
	printf("--------------**********-------------\n\n");

}

3.3 주소 할당

/**
 * 地址分配测试
 */
void basicAddressTest() {
	printf("------basicAddressTest开始测试-------\n");
	DLNode tempNode1, tempNode2;

	tempNode1.data = 4;
	tempNode1.next = NULL;

	tempNode2.data = 6;
	tempNode2.next = NULL;

	printf("第一个节点,data,next: %d, %d, %d\r\n",
	       &tempNode1, &tempNode1.data, &tempNode1.next);
	printf("第二个节点,data,next: %d, %d, %d\r\n",
	       &tempNode2, &tempNode2.data, &tempNode2.next);

	tempNode1.next = &tempNode2;
	printf("--------------**********-------------\n\n");

}

3.4 실행 결과

----insertDeleteTest开始测试-----

插入元素H成功!
插入元素e成功!
插入元素l成功!
插入元素l成功!
插入元素o成功!
插入元素!成功!
Hello!
你已经删除了节点e节点a不存在
你已经删除了节点oHll!
插入元素o成功!
Holl!
--------------**********-------------

----insertLocateTest开始测试-----

插入元素H成功!
插入元素e成功!
插入元素l成功!
插入元素l成功!
插入元素o成功!
插入元素!成功!
Hello!
元素e的位置是2
找不到元素a!!!
元素o的位置是5
Hello!
插入元素o成功!
Hoello!
--------------**********-------------

------basicAddressTest开始测试-------
第一个节点,data,next: -834668016, -834668016, -834668000
第二个节点,data,next: -834668048, -834668048, -834668032
--------------**********-------------


--------------------------------
Process exited after 0.06356 seconds with return value 0

Press ANY key to continue...

4 모든 코드

#include <stdio.h>
#include <malloc.h>

/**
 * 双链表结构体,存储字符串数据
 */
typedef struct DoubleLinkeNdode {
	char data;
	struct DoubleLinkeNdode *previous;
	struct DoubleLinkeNdode *next;
} DLNode, *DLNodePtr;

/**
 * @brief 初始化链表,创建一个头节点
 *
 * @return 返回头节点
 */
DLNodePtr initLinkList() {
	//申请空间
	DLNodePtr tempHeader = (DLNodePtr)malloc(sizeof(struct DoubleLinkeNdode) * 1);
	//初始化
	tempHeader->data = '\0';
	tempHeader->previous = NULL;
	tempHeader->next = NULL;
	return tempHeader;
}

/**
 * @brief 打印链表
 *
 * @param paraHeader 传入头节点
 */
void printList(DLNodePtr paraHeader) {
	DLNodePtr p = paraHeader->next;
	//节点不为空,则打印数据
	while (p != NULL) {
		printf("%c", p->data);
		p = p->next;
	}
	printf("\n");
}

/**
 * @brief 插入一个节点操作
 *
 * @param paraChar
 * @param paraHeader
 * @param paraPosition
 */
void insertElement(DLNodePtr paraHeader, char paraChar, int paraPosition) {
	//创建三个结构体变量:p查找查找插入链表位置,q申请新空间,r插入节点的后一节点,辅助插入
	DLNodePtr p, q, r;
	//1查找插入链表位置
	p = paraHeader;
	for (int i = 0; i < paraPosition; i++) {
		p = p->next;
		if (p == NULL) {
			printf("位置%d已经超出链表范围\n", paraPosition);
			return;
		}
	}

	//2申请空间
	q = (DLNodePtr)malloc(sizeof(struct DoubleLinkeNdode) * 1);
	//赋值
	q->data = paraChar;

	//3把新节点插入双链表
	r = p->next;
	q->next = p->next;
	q->previous = p;
	p->next = q;
	//如果不是尾节点,才需要把插入节点的后一节点指向插入节点(非常巧妙)
	if (r != NULL) {
		r->previous = q;
	}
	printf("插入元素%c成功!\n", paraChar);
}

/**
 * @brief 删除一个节点操作
 *
 * @param paraChar
 * @param paraHeader
 */
void deleteElement(DLNodePtr paraHeader, char paraChar) {
	//创建三个结构体变量:p为查找传入数据的前节点
	DLNodePtr p, q, r;
	//1查找传入数据的前节点
	p = paraHeader;
	while ((p->next != NULL) && (p->next->data != paraChar)) {
		p = p->next;
	}
	//2找不到数据,提示并结束
	if (p->next == NULL) {
		printf("节点%c不存在\n", paraChar);
		return;
	}
	//3找到数据,删除并提示
	q = p->next;
	r = q->next;
	p->next = r;
	if (r != NULL) {
		r->previous = p;
	}
	printf("你已经删除了节点%c", q->data);
	free(q);

}

/**
 * @brief 定位节点
 * 
 * @param paraChar 
 * @param paraHeader 
 * 
 * @return 
 */
int locateElement(DLNodePtr paraHeader, char paraChar) {
	DLNodePtr p = paraHeader;
	for (int i = 0; p != NULL; i++) {
		if (p->data == paraChar) return i;
		p = p->next;
	}
	return -1;
}

/**
 * 单元测试
 */
void insertDeleteTest() {
	printf("----insertDeleteTest开始测试-----\n");
	DLNodePtr tempList = initLinkList();
	printList(tempList);

	insertElement(tempList, 'H', 0);
	insertElement(tempList, 'e', 1);
	insertElement(tempList, 'l', 2);
	insertElement(tempList, 'l', 3);
	insertElement(tempList, 'o', 4);
	insertElement(tempList, '!', 5);
	printList(tempList);

	deleteElement(tempList, 'e');
	deleteElement(tempList, 'a');
	deleteElement(tempList, 'o');
	printList(tempList);

	insertElement(tempList, 'o', 1);
	printList(tempList);
	printf("--------------**********-------------\n\n");

}

/**
 * 单元测试2
 */
void insertLocateTest() {
	printf("----insertLocateTest开始测试-----\n");
	int location, data;
	DLNodePtr tempList = initLinkList();
	printList(tempList);

	insertElement(tempList, 'H', 0);
	insertElement(tempList, 'e', 1);
	insertElement(tempList, 'l', 2);
	insertElement(tempList, 'l', 3);
	insertElement(tempList, 'o', 4);
	insertElement(tempList, '!', 5);
	printList(tempList);

	data = 'e';
	location = locateElement(tempList, data);
	if (location == -1) {
		printf("找不到元素%c!!!\n", data);
	} else {
		printf("元素%c的位置是%d\n", data, location);
	}
	data = 'a';
	location = locateElement(tempList, data);
	if (location == -1) {
		printf("找不到元素%c!!!\n", data);
	} else {
		printf("元素%c的位置是%d\n", data, location);
	}
	data = 'o';
	location = locateElement(tempList, data);
	if (location == -1) {
		printf("找不到元素%c!!!\n", data);
	} else {
		printf("元素%c的位置是%d\n", data, location);
	}
	printList(tempList);

	insertElement(tempList, 'o', 1);
	printList(tempList);
	printf("--------------**********-------------\n\n");

}

/**
 * 地址分配测试
 */
void basicAddressTest() {
	printf("------basicAddressTest开始测试-------\n");
	DLNode tempNode1, tempNode2;

	tempNode1.data = 4;
	tempNode1.next = NULL;

	tempNode2.data = 6;
	tempNode2.next = NULL;

	printf("第一个节点,data,next: %d, %d, %d\r\n",
	       &tempNode1, &tempNode1.data, &tempNode1.next);
	printf("第二个节点,data,next: %d, %d, %d\r\n",
	       &tempNode2, &tempNode2.data, &tempNode2.next);

	tempNode1.next = &tempNode2;
	printf("--------------**********-------------\n\n");

}



int main() {
	insertDeleteTest();
	insertLocateTest();
	basicAddressTest();
	return 0;
}

추천

출처blog.csdn.net/qq_61649579/article/details/124549972