!!! 4.双链表
? 线性表 ?    2017-09-02 01:23:05    275    0    0
simon88   ? 线性表 ?

双链表

1、双向链表(Double Linked List)
     双(向)链表中有两条方向不同的链,即每个结点中除next域存放后继结点地址外,还增加一个指向其直接前趋的指针域prior。

注意:
     ①双链表由头指针head惟一确定的。
     ②带头结点的双链表的某些运算变得方便。
     ③将头结点和尾结点链接起来,为双(向)循环链表。
2、双向链表的结点结构和形式描述

①结点结构(见上图a)
 
     
②形式描述

    typedef struct dlistnode{
          DataType data;
          struct dlistnode *prior,*next;
       }DListNode;
     typedef DListNode *DLinkList;
     DLinkList head;​



3、双向链表的前插和删除本结点操作
     由于双链表的对称性,在双链表能能方便地完成各种插入、删除操作。
①双链表的前插操作
    

    void DInsertBefore(DListNode *p,DataType x)
      {//在带头结点的双链表中,将值为x的新结点插入*p之前,设p≠NULL
        DListNode *s=malloc(sizeof(DListNode));//①
        s->data=x;//②
        s->prior=p->prior;//③
        s->next=p;//④
        p->prior->next=s;//⑤
        p->prior=s;//⑥
       }
②双链表上删除结点*p自身的操作

void DDeleteNode(DListNode *p)
      {//在带头结点的双链表中,删除结点*p,设*p为非终端结点
          p->prior->next=p->next;//①
          p->next->prior=p->prior;//②
          free(p);//③
      }
注意:
     与单链表上的插入和删除操作不同的是,在双链表中插入和删除必须同时修改两个方向上的指针。
     上述两个算法的时间复杂度均为O(1)。

 

例子:

1.结构和函数原型:

/*
 * d_linklist.h
 *
 *  Created on: 2017年10月18日
 *      Author: simon
 */

#ifndef D_LINKLIST_H_
#define D_LINKLIST_H_

#include "s_linklist.h"	//引用typedef int type;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


typedef struct d_node {
	type data;
	struct d_node *prev;
	struct d_node *next;
}D_NODE,*D_PNODE;
typedef struct d_head {
	D_PNODE tail;		//指向尾节点
	D_PNODE head;		//指向头结点
	int length;			//双向链表的长度
}D_ROOT,*D_PROOT;

//创建一个节点并且赋值为data
D_PNODE d_makenode_linklist(type data);
//初始化双向链表
D_PROOT d_init_linklist(void);
//改变根节点中记录链表数组大小的标记
void d_resizemark_linklist(D_PROOT d_root,int length);
//遍历链表并且打印
void d_printfall_linklist(D_PROOT d_root);
//释放node所指的节点
void d_freenode_linklist(D_PNODE node);
//摧毁一个双向链表
void d_destory_linklist(D_PROOT d_root);
//往双向链表头部添加节点
void d_addhead_linklist(D_PROOT d_root,D_PNODE node);
//往双向链表尾部插入节点
void d_addtail_linklist(D_PROOT d_root,D_PNODE node);
#endif /* D_LINKLIST_H_ */

2.函数

/*
 * d_linklist.c
 *
 *  Created on: 2017年10月18日
 *      Author: simon
 */

#include "../include/d_linklist.h"

//创建一个节点并且赋值为data
D_PNODE d_makenode_linklist(type data)
{
	D_PNODE node = (D_PNODE)malloc(1*(sizeof(D_NODE)));
	if(node == NULL) {
		printf("allocation failure\n");
		return NULL;
	}
	node->data = data;
	node->next = node->prev = NULL;
	return node;
}
//改变根节点中记录链表数组大小的标记
void d_resizemark_linklist(D_PROOT d_root,int length)
{
	d_root->length = length;
	return ;
}

//初始化双向链表
D_PROOT d_init_linklist(void)
{
	D_PROOT root = (D_PROOT)malloc(1*sizeof(D_ROOT));
	D_PNODE node = d_makenode_linklist(0);
	if(root == NULL || node == NULL) {
		printf("allocation failure\n");
		exit(EXIT_FAILURE);
	}
	d_resizemark_linklist(root,1);
	root->head = node;
	root->tail = node;
	return root;
}
//遍历链表并且打印
void d_printfall_linklist(D_PROOT d_root)
{
	if(d_root->head == NULL || d_root == NULL) {
		printf("linklist is empty\n");
		return ;
	}
	D_PNODE p = d_root->head;
	printf("%d\t",p->data);
	while(p->next != d_root->head) {
		p = p->next;
		printf("%d\t",p->data);
	}
	return ;
}
//释放node所指的节点
void d_freenode_linklist(D_PNODE node)
{
	free(node);
}
//摧毁一个双向链表
void d_destory_linklist(D_PROOT d_root)
{
	if(d_root == NULL) {
		return ;
	}
	if(d_root->head == NULL) {
		free(d_root);
		d_root = NULL;
		return ;
	}
	D_PNODE node = d_root->head;
	while(node != NULL) {
		free(node);
		node = node->next;
	}
	node = NULL;
	return ;
}
//往双向链表头部添加节点
void d_addhead_linklist(D_PROOT d_root,D_PNODE node)
{
	if(d_root == NULL) {
		printf("root is NULL\n");
		exit(EXIT_FAILURE);
	}
	if(node == NULL) {
		printf("node is NULL\n");
		return ;
	}
	if(d_root->head == NULL) {
		printf("null\n");
		d_root->head = node;
		d_root->tail = node;
		d_resizemark_linklist(d_root,d_root->length+1);
		return ;
	}
	node->next = d_root->head;
	node->prev = d_root->tail;
	d_root->head->prev = node;
	d_root->tail->next = node;
	d_root->head = node;
	d_resizemark_linklist(d_root,d_root->length+1);
	return ;
}
//往双向链表尾部插入节点
void d_addtail_linklist(D_PROOT d_root,D_PNODE node)
{
	if(d_root == NULL) {
		printf("root is NULL\n");
		exit(EXIT_FAILURE);
	}
	if(node == NULL) {
		printf("node is NULL\n");
		return ;
	}
	if(d_root->tail == NULL) {
		printf("null\n");
		d_root->head = node;
		d_root->tail = node;
		d_resizemark_linklist(d_root,d_root->length+1);
		return ;
	}
	node->next = d_root->head;
	node->prev = d_root->tail;
	d_root->head->prev = node;
	d_root->tail->next = node;
	d_root->tail = node;
	d_resizemark_linklist(d_root,d_root->length+1);
}

 3.测试函数

//初始化双向链表
	D_PROOT d_root =  d_init_linklist();
	printf("length:%d\n",d_root->length);
	int i=0;
	D_PNODE node;
	for(i=0;i<800;i++) {
		node = d_makenode_linklist(i+1);
		d_addhead_linklist(d_root,node);
	}
	d_printfall_linklist(d_root);
	printf("length:%d\n",d_root->length);

	for(i=0;i<800;i++) {
		node = d_makenode_linklist(i+1);
		d_addtail_linklist(d_root,node);
	}
	d_printfall_linklist(d_root);
	printf("length:%d\n",d_root->length);
	d_destory_linklist(d_root);
	node = NULL;
	d_root = NULL;

 

上一篇: 2.顺序表上实现的基本运算

下一篇: 5.顺序表和链表的比较

275 人读过
0 条评论