文章目录
线性表的链式存储结构(双向链表)
这里是数据结构个人学习的笔记记录,如有问题欢迎指正说明
双向链表的定义
n个结点链结成一个链表。每个结点由数据域和指针域两部分组成,在此处我们研究结点含两个个指针域的链表,一个直接前驱指针,一个直接后继指针,即双向链表。
结点的表示方法:
typedef struct DoubleLinkedNode
{
char data;
struct DoubleLinkedNode* previous;
struct DoubleLinkedNode* next;
}DLNode,*DLNodePtr;
双向链表的相关操作实现
初始化
/* 初始化 */
DLNodePtr initLinkList()
{
DLNodePtr tempHeader=(DLNodePtr)malloc(sizeof(struct DoubleLinkedNode));
tempHeader->data='\0';
tempHeader->previous=NULL;
tempHeader->next=NULL;
return tempHeader;
}
依次对单链表中的每个数据元素输出
/* 依次对链表中的每个数据元素输出 */
void printList(DLNodePtr paraHeader){
DLNodePtr p=paraHeader->next;
while(p!=NULL){
printf("%c",p->data);
p=p->next;
}
printf("\r\n");
}
在双向链表中指定位置之后插入新的数据元素
/* 在链表中指定位置paraPosition之前插入新的数据元素paraChar */
void insertElement(DLNodePtr paraHeader, char paraChar, int paraPosition)
{
DLNodePtr p, s, r;
// Step 1. Search to the position.
p = paraHeader;
for (int i = 0; i < paraPosition; i ++) {
p = p->next;
if (p == NULL) {
printf("The position %d is beyond the scope of the list.", paraPosition);
return;
}// Of if
} // Of for i
// Step 2. Construct a new node.
s = (DLNodePtr)malloc(sizeof(struct DoubleLinkedNode));
s->data = paraChar;
// Step 3. Now link.
r = p->next;
s->next = p->next;
s->previous = p;
p->next = s;
if (r != NULL) {
r->previous = s;
}
}
删除线性表中指定的数据元素
/* 删除链表的指定的数据元素paraChar */
void deleteElement(DLNodePtr paraHeader, char paraChar){
DLNodePtr p, q, r;
p = paraHeader;
// Step 1. Locate.
while ((p->next != NULL) && (p->next->data != paraChar)){
p = p->next;
}// Of while
// Step 2. Error check.
if (p->next == NULL) {
printf("The char '%c' does not exist.\r\n", paraChar);
return;
}// Of if
// Step 3. Change links.
q = p->next;
r = q->next;
p->next = r;
if (r != NULL) {
r->previous = q;
}// Of if
// Step 4. Free the space.
free(q);
}
新增操作
返回链表中元素的个数
/* 返回链表中数据元素个数 */
int listLength(DLNodePtr paraHeader)
{
int i=0;
DLNodePtr paraNew=paraHeader->next;
while(paraNew)
{
i++;
paraNew=paraNew->next;
}
return i;
}
返回指定位序的值
/* 返回链表中第i个数据元素的值 */
char getElement(DLNodePtr paraHeader,int i)
{
int j=1;
DLNodePtr p;
p=paraHeader->next;
while(p&&j<i)
{
p=p->next;
++j;
}
if(!p||j>i)
{
printf("Invalid number!\n");
return -1;
}
return p->data;
}
返回第一个满足指定数据元素的位序
/* 返回链表中第1个与paraChar满足关系的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
int locateElement(DLNodePtr paraHeader, char paraChar)
{
int i=0;
DLNodePtr p=paraHeader->next;
while(p)
{
i++;
if(p->data==paraChar)
return i;
p=p->next;
}
return 0;
}
整表删除
/* 初始条件:链式已存在。操作结果:将链表重置为空表 */
void clearList(DLNodePtr paraHeader)
{
DLNodePtr p,q;
p=paraHeader->next;
while(p)
{
q=p->next;
free(p);
p=q;
}
paraHeader->next=NULL;
}
双向链表的代码实现
#include<stdio.h>
#include<stdlib.h>
typedef struct DoubleLinkedNode
{
char data;
struct DoubleLinkedNode* previous;
struct DoubleLinkedNode* next;
}DLNode,*DLNodePtr;
DLNodePtr initLinkList()
{
DLNodePtr tempHeader=(DLNodePtr)malloc(sizeof(struct DoubleLinkedNode));
tempHeader->data='\0';
tempHeader->previous=NULL;
tempHeader->next=NULL;
return tempHeader;
}
void printList(DLNodePtr paraHeader){
DLNodePtr p=paraHeader->next;
while(p!=NULL){
printf("%c",p->data);
p=p->next;
}
printf("\r\n");
}
void insertElement(DLNodePtr paraHeader, char paraChar, int paraPosition){
DLNodePtr p, s, r;
// Step 1. Search to the position.
p = paraHeader;
for (int i = 0; i < paraPosition; i ++) {
p = p->next;
if (p == NULL) {
printf("The position %d is beyond the scope of the list.", paraPosition);
return;
}// Of if
} // Of for i
// Step 2. Construct a new node.
s = (DLNodePtr)malloc(sizeof(struct DoubleLinkedNode));
s->data = paraChar;
// Step 3. Now link.
r = p->next;
s->next = p->next;
s->previous = p;
p->next = s;
if (r != NULL) {
r->previous = s;
}
}
void deleteElement(DLNodePtr paraHeader, char paraChar){
DLNodePtr p, q, r;
p = paraHeader;
// Step 1. Locate.
while ((p->next != NULL) && (p->next->data != paraChar)){
p = p->next;
}// Of while
// Step 2. Error check.
if (p->next == NULL) {
printf("The char '%c' does not exist.\r\n", paraChar);
return;
}// Of if
// Step 3. Change links.
q = p->next;
r = q->next;
p->next = r;
if (r != NULL) {
r->previous = q;
}// Of if
// Step 4. Free the space.
free(q);
}
int locateElement(DLNodePtr paraHeader, char paraChar)
{
int i=0;
DLNodePtr p=paraHeader->next;
while(p)
{
i++;
if(p->data==paraChar)
return i;
p=p->next;
}
return 0;
}
char getElement(DLNodePtr paraHeader,int i)
{
int j=1;
DLNodePtr p;
p=paraHeader->next;
while(p&&j<i)
{
p=p->next;
++j;
}
if(!p||j>i)
{
printf("Invalid number!\n");
return -1;
}
return p->data;
}
int listLength(DLNodePtr paraHeader)
{
int i=0;
DLNodePtr paraNew=paraHeader->next;
while(paraNew)
{
i++;
paraNew=paraNew->next;
}
return i;
}
void clearList(DLNodePtr paraHeader)
{
DLNodePtr p,q;
p=paraHeader->next;
while(p)
{
q=p->next;
free(p);
p=q;
}
paraHeader->next=NULL;
}
void insertDeleteTest(){
// Step 1. Initialize an empty list.
DLNodePtr tempList = initLinkList();
printList(tempList);
// Step 2. Add some characters.
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);
printf("'o' is at the %d position in the linked list\n",locateElement(tempList,'o'));
printf("The second element is %c\n",getElement(tempList,2));
// Step 3. Delete some characters (the first occurrence).
deleteElement(tempList, 'e');
deleteElement(tempList, 'a');
deleteElement(tempList, 'o');
printList(tempList);
printf("Length of the list is %d\n",listLength(tempList));
// Step 4. Insert to a given position.
insertElement(tempList, 'o', 1);
printList(tempList);
clearList(tempList);
printf("Afer clear,print list:\n");
printList(tempList);
}
void basicAddressTest(){
DLNode tempNode1, tempNode2;
tempNode1.data = 'a';
tempNode1.next = NULL;
tempNode2.data = 'c';
tempNode2.next = NULL;
printf("The first node: %d, %d, %d\r\n",
&tempNode1, &tempNode1.data, &tempNode1.next);
printf("The second node: %d, %d, %d\r\n",
&tempNode2, &tempNode2.data, &tempNode2.next);
tempNode1.next = &tempNode2;
}
void main(){
insertDeleteTest();
basicAddressTest();
}
样例测试输出
Hello!
‘o’ is at the 5 position in the linked list
The second element is e
The char ‘a’ does not exist.
Hll!
Length of the list is 4
Holl!
Afer clear,print list:The first node: 6421968, 6421968, 6421984
The second node: 6421936, 6421936, 6421952
双向链表相对于单链表的优缺点
优点:它具有良好的对称性,因此对某个结点的前后结点的操作很方便,有效提高了算法性能。
缺点:相比单链表更加复杂,增加了一个previous指针,在空间上占用会多一些。
写在最后
双向链表说白了其实就是空间换时间,还有我们用双向链表在实现一些插入和删除操作的时候要注意指针指向的变化。