今天学习的是双向链表,比起单链表来说应用会更加广泛,和单链表的算法在少数地方有些许差异。
老师的代码
创建一个双向链表
双向链表在结构体的定义上多增加了一个指向前一个的指针域。
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->next =NULL;
tempHeader->previous =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,q,r;
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;
}
}
q=(DLNodePtr)malloc(sizeof(struct DoubleLinkedNode));
q->data =paraChar;
r=p->next ;
q->next =p->next ;
q->previous =p;
p->next =q;
if(r!=NULL)
{
r->previous =q;
}
}
双向链表的创建和输出都与单链表的没有什么区别,但是插入这里进行了些许改变,我先用展示图解再加以阐述:
在这里插入图片描述](https://img-blog.csdnimg.cn/150eaaf4af8144909af1ae0b5a82a318.png)
通过这幅图解,我们清楚的了解双向链表进行插入的四个步骤:
1.定义一个临时节点p,使p挪动到我们想要插入的节点的位置,再定义一个临时节点q,q的数据域等于我们想要插入的值;
2.使q的next指向p的下一个节点;
3.q的previous指向p节点;
4.p的next指向q节点;(3,4步都是将p与q连接在一起)
需要注意的是,我们定义了一个临时节点r用于存储p所指向的下一个节点,在这里我们首先要判断r是否为空(为空的话自然就不存在previous了),若不为空,则使它的previous指向q节点,q就与p的下一个节点连接起来了。
这样,q节点就成功的插入在p节点之后了。
删除
//删除
void deleteElement(DLNodePtr paraHeader,char paraChar){
DLNodePtr p,q,r;
p=paraHeader;
while(p->next !=NULL&&p->next ->data!=paraChar)
{
p=p->next ;
}
if(p->next ==NULL)
{
printf("The char '%c' does not exist.\r\n",paraChar);
return;
}
q=p->next ;
r=q->next ;
p->next =r;
if(r!=NULL)
{
r->previous =p;
}
free(q);
}
先展示图解,再说明步骤:
删除比较简单,在这里也只进行简单的步骤说明:
1.同样先定义一个临时节点p,将p挪动到我们想要删除元素的前一个节点处;
2.定义一个临时节点q,将q指向p节点的下一个节点;
3.定义一个临时节点r,使r指向q的下一个节点;
4.使p指向r;
这里同样需要判断r是否为空,如果不为空,则将r回指到p并且释放q。
测试代码
//测试代码
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);
// Step 3. Delete some characters (the first occurrence).
deleteElement(tempList, 'e');
deleteElement(tempList, 'a');
deleteElement(tempList, 'o');
printList(tempList);
// Step 4. Insert to a given position.
insertElement(tempList, 'o', 1);
printList(tempList);
}
void basicAddressTest(){
DLNode tempNode1, tempNode2;
tempNode1.data = 4;
tempNode1.next = NULL;
tempNode2.data = 6;
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 printfList2(DLNodePtr paraHeader)
{
DLNodePtr p=paraHeader;
while (p->next != NULL) {
p = p->next;
}
while(p!=paraHeader)
{
printf("%c",p->data );
p=p->previous ;
}
printf("\r\n");
}
运行结果如下: