双向链表
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
1.定义
include<stdio.h>
include<string.h>
typedef struct{
int data;//结点中的数据 struct Node* prev;//结点中指向前一个节点的指针(因为Node结构体是在后面重定义的所以这里还要加struct)
struct Node* next;//结点中指向下一个节点的指针
}Node;//一个结点
Node* head=NULL;
Node* tail=NULL;//把头和尾都赋值为空值;定义的是指针即为一个地址
int len=0;//链表的初始长度为0
2. 创建一个结点
sizeof是关键字,它以字节的形式给出了其操作数的存储大小
malloc函数用于动态申请内存空间,适用于申请一个未定大小的数据集合的申请。
Node* createNode(char dat)//为指针函数因为最后的返回值是一个指针
{
Node* ptr;//一个Node型的指针变量里面存放的是地址
ptr = malloc(sizeof(Node));//用malloc函数和sizeof关键字分配地址(sizeof来测量出Node类型的内存大小,malloc函数用来分配地址)
if(ptr == NULL)//如果这个结点为0就退出
{
exit(1);//退出
}
//继续执行
ptr->data=dat;//将dat的值赋值给节点中的data
ptr->prev=NULL;//因为只是创建一个结点不知道放在哪所以前后都是空
ptr->prev=NULL;
return ptr;//返回ptr 为一个地址
}
3.在开头插入
void addfirst(int dat){
Node* ptr = createNode(dat);//利用之前创造结点的函数创造一个结点
if(len){
ptr->next=head;//将head放在ptr的后面 ptr就变成了第一个
head->prev=ptr;//将向前的指针也做好维护 讲head的前面指向ptr
head=ptr;//ptr就变成了头结点 所以赋值给head
}else{
head=ptr;//赋值给头尾(就一个为头尾)
tail=ptr;}
len++
}
4.得到第几个结点(即链表中第几个data)
因为是双向链表所以双向遍历更有效率
Node* get(int index){
int i;
Node* ptr;
if(index<0||index>=len){ //判断index是否在范围内
printf("index is illegal");
exit(1);}
//如果要查找的在前一半用向后的指针找
if(index<(len/2)){
ptr=head;
for(i=0;i<index;i++){
ptr=ptr->next;//指向下一个(把下一个赋值给他)
}else{//查找的在后一半用 向前找
ptr=tail;//指向前一个(把前一个赋值给他)
for(i=0;i<len-index-1;i++){
ptr=ptr->prev;}
}return ptr;
}
5.在指定位置插入
void add(int dat,int index){
Node* ptr,*prevptr,*nextptr;//因为双向链表所以前后的指针都要维护
if(index<0||index>=len){
printf("index is illegal!");
exit(1);//判断index是否在范围内
}
ptr=createNode(dat);
if(index==0)
{
addfirst(dat);
}//如果在开头插入就调用之前定义的addfirst
else{
prevptr=get(index-1);//先找到要插入为位置的前一个
nextptr=prev->next;//将要插入位置的元素放在后一个上
ptr->next=nextptr;//将要插入的结点ptr的next指针指向nextptr即为本来要插入的位置上的元素
ptr->prev=prevptr;//将要插入的结点ptr的prev指针指向prevptr即为本来要插入的元素的前一个
nextptr->prev=ptr;//将nextptr的前一个和prevptr的后一个分别赋值ptr
prevptr->next=ptr;
len++;
}
6. 在尾端插入一个元素
void addlast(char dat){
if(len==0){//如果长度为0即插入第一个可以调用addfirst
addfirst(dat);}
else{Node* ptr=createnode(dat);
tail->next=ptr;//将ptr赋给tail的next
ptr->prev=tail;//将tail赋值给tail前面的一个
tail=ptr;//将ptr给tail ptr->next 为 NUll即将插入的变成tail
len++;
}
7.删除
void delete(int index){
Node* temp = head;//用temp指向head
Node* prevptr = NULL, *curptr = NULL, *nextPtr = NULL;
if(index < 0 || index >= len){//判断是否在链表里
printf("index is illegal!");
exit(1);
}
if(index == 0){//判断为第1个元素
head = head->next;//直接指向头结点后面一个
free(temp);//用free释放内存
}else {
prevptr = get(index-1);//得到第index的结点即前面一个的
curptr = prevptr->next;//curptr为第index要删除的;
nextptr = curptr->next;//nextprt为第index第index+1个
if(nextPtr == NULL){//如果第index+1为NULL
tail = prevptr;//前一个结点变成尾
}
nextptr->prev=prevptr;//第index的后一个的结点指向prevptr
prevptr->next = nextptr;//第index-1的next指向第index+1个
free(curPtr);//释放内粗
}
len--;
}
8. 输出所有元素
void travel(){
int i = len;
Node* ptr = head;//定义开始为头指针
while(i--){
printf("add:%x,%c,next:%x\n",ptr,ptr->data,ptr->next);
ptr = ptr->next;}//指向下一个
}
例子:
#include <stdio.h>
typedef struct {
int dat;
struct Node * prev; //point to the previous node
struct Node * next; //point to the next node
} Node;
Node * head = NULL, *tail = NULL;
int len = 0;
//functions
Node* createNode(int dat){
Node *ptr;
ptr = malloc(sizeof(Node));
if(ptr == NULL){
exit(1);
}
ptr->dat = dat;
ptr->prev = NULL;
ptr->next = NULL;
return ptr;
}
//insert a element before the linklist
void addFirst(int dat){
Node *ptr = createNode(dat);
if(len){
ptr->next = head;
head->prev = ptr;
head = ptr;
}else{
head = ptr;
tail = ptr;
}
len++;
}
//get element by index
Node * get(int index){
int i = 0;
Node* ptr;
if(index < 0 || index >= len){
printf("index is illegal!");
exit(1);
}
if(index < len/2){
ptr = head;
for(;i<index;i++){
ptr = ptr->next;
}
printf("execute times:%d\n", index);
}else{
ptr = tail;
for(;i<len-index-1;i++){
ptr = ptr->prev;
}
printf("execute times:%d\n", len-index-1);
}
return ptr;
}
//insert a data to the middle of linklist
//index < len
void add(int dat, int index){
Node *ptr, *prevPtr, *nextPtr;
if(index < 0 || (len > 0 && index >= len) ){
printf("index is illegal!");
exit(1);
}
ptr = createNode(dat);
if(index == 0){
addFirst(dat);
}else{
prevPtr = get(index-1);
nextPtr = prevPtr->next;
ptr->next = nextPtr;
nextPtr->prev = ptr;
prevPtr->next = ptr;
ptr->prev = prevPtr;
len++;
}
}
//append a element to the end
void addLast(int dat){
if(len == 0){
addFirst(dat);
}else{
Node *ptr = createNode(dat);
tail->next = ptr;
ptr->prev = tail;
tail = ptr;
len++;
}
}
//remove the element located by the index
void delete(int index){
Node* temp = head, *prevPtr = NULL, *curPtr = NULL, *nextPtr = NULL;
if(index < 0 || index >= len){
printf("index is illegal!");
exit(1);
}
if(index == 0){
head = head->next;
free(temp);
}else {
prevPtr = get(index-1);
curPtr = prevPtr->next;
nextPtr = curPtr->next;
if(nextPtr == NULL){
tail = prevPtr;
}
prevPtr->next = nextPtr;
free(curPtr);
}
len--;
}
//display all elements
void travel(){
int i = len;
Node* ptr = head;
while(i--){
printf("addr:%x, %d, next:%x, head:%x, tail:%x\n", ptr, ptr->dat, ptr->next, head, tail);
ptr = ptr->next;
}
}
void main() {
int i= 1, dat;
for(;i<=1000;i++){
addLast(i);
}
printf("len:%d\n", len);
travel();
printf("---------\n");
dat = get(5)->dat;
printf("dat:%d\n", dat);
dat = get(995)->dat;
printf("dat:%d\n", dat);
}