链表ALDS1-3-C:Doubly Linked List

时间:2022-09-05 19:52:14

         如图4.8所示,表中的各元素称作“结点”。双向链表的结点是结构体,由数据本体(这里是整数key)、指向前一元素的指针prev以及指向后一元素的指针next组成。这些结构体通过指针连接成一个链,就形成了双向链表。

链表ALDS1-3-C:Doubly Linked List

program4.3 C++双向链表的结点

strcut Node {
   int key;
   Node *prev, *next; 
};

        另外,在表头设置一个特殊的结点可以简化链表的实现。我们将这个结点称为“头结点”。头结点中虽然不包含实际数据,但他可以让我们更轻松的对链表做更改。比如加入头结点之后,我们将更容易实现删除元素的操作。



      init函数用于初始化链表。如图4.9所示,它会生成一个NIL结点作为链表的头结点,然后让prev和next都指向这个结点,从而创造一个空表。

链表ALDS1-3-C:Doubly Linked List

program4.4 初始化双向链表

Node *nil;

void init() {
	nil = (Node *)malloc(sizeof(Node));
	nil->next = nil;
	nil->prev = nil;
} 
        头结点是添加元素的起点。这里的malloc是C语言标准库中的函数,用于动态申请指定大小的空间。另外,“->”是通过指针变量访问成员的运算符,称为箭头运算符。




        insert函数用于生成包含所输入键值的结点,并将该结点添加到标的开头。如图4.10所示这个函数会以头结点为起点分四步改变指针所指的方向。

链表ALDS1-3-C:Doubly Linked List

program4.5 往双向表中插入元素

void insert(int key) {
	Node *x = (Node *)malloc(sizeof(Node));
	x->key = key;
	//在头结点后添加元素
	x->next = nil->next;
	nil->next->prev = x;
	nil->next = x;
	x->prev = nil; 
} 




      listSearch函数用于搜索元素,它可以在链表中寻找包含指定键值的结点,并返回其指针。假设cur为指向当前位置结点的指针,只要从头结点的next所指的结点,即链表开头的元素开始逐个执行cur = cur -> next,即可逐一访问每个结点。

program4.6 在双向链表中搜索元素

Node* listSearch(int key) {
	Node *cur = nil->next;  //从头结点后面的元素开始访问
	while( cur != nil && cur->key != key) {
		cur = cur->next;
	} 
	retrun cur;
}

        在访问过程中发现key或者指针回到头结点NIL时结束搜索,并返回此时cur的值。




        deleteNode函数会通过如图4.11所示的步骤改变指针所指的位置,从而删除指定的结点t。在C++中,我们必须手动释放已删除结点的内存。这里的free时C语言标准库中的函数,用于释放已不需要的内存空间。

链表ALDS1-3-C:Doubly Linked List

program4.7 从双向链表中删除元素

void deleteNode(Node *t) {
	if( t == nil )  return;
	t->prev->next = t->next;
	t->next->prev = t->prev;
	free(t);
}

void deleteFirst() {
	deleteNode( nil->next );
}

void deleteLast() {
	deleteNode( nil->prev );
}

void deleteKey(int key)  {
	//删除已搜索到的结点
	deleteNode( listSearch(key)); 
}




例题;

链表ALDS1-3-C:Doubly Linked List链表ALDS1-3-C:Doubly Linked List

代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
struct Node  {
	int key;
	Node *next,*prev;
};

Node *nil;

void init()  {      //初始化 
	nil = (Node *)malloc(sizeof(Node));
	nil->next = nil;
	nil->prev = nil;
}

Node* listSearch(int key)  {    //找出含有键值key的结点 
    Node *cur = nil->next;
    while( cur != nil && cur->key != key)  {
    	cur = cur->next;
	}
	return cur;
}

void insert(int key)  {       //在头节点后插入某个元素 
	Node *x = (Node *)malloc(sizeof(Node));
	x->key = key;
	x->next = nil->next;
	nil->next->prev = x;
	nil->next = x;
	x->prev = nil;
}

void deleteNode(Node *t)  {     //删除结点 被下面调用函数  调用 
	if( t == nil)  return;
	t->prev->next = t->next;
	t->next->prev = t->prev;
	free(t);  //释放已经不需要的内存空间 
}

void deleteFirst()  {    //删除头结点next所指向的结点 
	deleteNode(nil->next);
}

void deleteLast()  {    //删除头结点prev所指向的结点 
	deleteNode(nil->prev);
}

void deleteKey(int key) {
	deleteNode(listSearch(key));  //删掉搜索到的结点 
}

void printList()  {      //打印链表 
	Node *cur = nil->next;
	int isf = 0;
	while(1)  {
		if( cur == nil ) break;
		if(isf++ > 0) printf(" ");
		printf("%d",cur->key);
		cur = cur->next;
	}
	printf("\n");
} 
int main()
{
	int n,key,i;
	char com[20];
	cin>>n;
	init();
	int size = 0,np = 0,nd = 0;
	for( i=0; i<n; i++ )  {
		scanf("%s%d",com,&key);
		if( com[0] == 'i')  {  insert(key);  np++;  size++;}
			 else if( com[0] == 'd')  {
			if( strlen(com) > 6)  {
				if( com[6] == 'F')  deleteFirst();
				else if( com[6] == 'L')  deleteLast();
				}  else  {
					deleteKey(key);  nd++;
				}
				size--;
			}
		}
		printList();
	return 0;
}
/*
7
insert 5 
insert 2
insert 3
insert 1
delete 3
insert 6
delete 5
*/