前面先贴出我之前才学双向链表写的总结,也许更贴近我才接触的感受,虽然也没过去多久。贴出的代码则是我重新写的和之前写的还是有点不一样(写的要稍微好一点点点),前面这就作为代码思想的注释吧,而且我只列出当时重点怎么理解的部分。
不过还是先贴出结构体:
typedef struct Node {
int data;
structNode *prior;//前驱
structNode *next;//后继
}Node, *pNode;
the past:
双向链表对比与单向链表,具有前驱和后继,双向链表还是蛮有趣的,因为他从前往后和从后往前都可以知道链表的值,我也看了很久。从头开始学习算法真心不容易,请允许我这个渣慢慢进步啊。
pNode Init() {
pNodeL = (pNode )malloc(sizeof(Node));
if(!L) {
printf("failed\n");
exit(-1);
}
L->next = L->prior = NULL;//初始化头结点的前驱后继都为空
//好像得有返回量 我用void型就写出问题 唉。。。
returnL ;
}
//头插法
//头插法在于头永远都在那里不会变 相对来说操作很死板
void PreInsert(pNode L,int item) {
pNodep = L;
pNodepNew = (pNode)malloc(sizeof(Node));
pNew->data= item;
pNew->prior= p;
pNew->next= p->next;
p->next= pNew;
return;
}
//尾插法
//我想了好久也是醉了
/*
尾插法在于每次都在最后一个节点后面插入,所以关键是怎么处理怎么设置出tail这个节点
我原先的写法:
voidTailInsert(pNode L, int item) {
pNodetail = L;
pNodepNew = (pNode)malloc(sizeof(Node));
pNew->data= item;
tail->next= pNew;
pNew->prior= tail;
pNew->next= NULL;
tail= pNew;
}
main函数里这样
pNodeL;
L= Init();
printf("\n尾插法:\n");
TailInsert(tail,8);
TailInsert(tail,9);
TailInsert(tail,1);
TailInsert(tail,2);
Traverse(L);//结果就一个数据
我的想法是每次在tail节点后插入一个新节点,然后在把最后这个新节点变成tail节点,这样不就行了么。
这段代码错误就在于pNode tail = L;这一句导致的结果就是每次执行插入函数,又特么的从开始的尾插入,
也就是永远只能插入一个数据(执行遍历就一个值)。
所以我就在想怎么让这个tail随着链表长度变化他一直在链表的最后位置。
想啊想,真特么的烦啊
本来我还想设个全局变量,把pNode L作为全局变量在放入函数里不就不会每次都变了,但那不就整个程序就变味了么唉。。
后来我就试着把pNode tail = L 去掉,然后在main函数里这样写
pNodeL;
L= Init();
pNodetail = L;
printf("\n尾插法:\n");
TailInsert(tail,8);
TailInsert(tail,9);
TailInsert(tail,1);
TailInsert(tail,2);
Traverse(L);
这样写pNode L;
L= Init();
pNodetail = L;就能让tail一直成为尾巴了,而原本的头一直没变
然后测试还特么的一个数据
想啊想
最后想到(不是凭技术想出来的)我最近写链表时遇到的,就是传引用到函数里,就是TailInsert(pNode &tail, int item)酱紫
我想了想,自我理解是因为tail直接传进去无法传回来,只能传引用才会变,只能酱紫
理解了
怎么说总算搞出来了
2015/1/12/17:19
*/
void TailInsert(pNode &tail, int item){
pNodepNew = (pNode)malloc(sizeof(Node));
pNew->data= item;
tail->next= pNew;
pNew->prior= tail;
pNew->next= NULL;
tail= pNew;
}
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
typedef int datatype;
typedef struct Node {
datatype data;
struct Node *prior;//前驱
struct Node *next;//后继
}Node, *pNode;
//===============================
void Init(pNode &L);//初始化
void PreInsert(pNode &L, datatype item);//前插法
void TailInsert(pNode &L, datatype item);//尾插法
void DeleteNode(pNode &L, datatype &item);//删除节点
void DelteList(pNode &L);//删除链表
void Traverse(pNode L);//遍历
//==================================================
//初始化
void Init(pNode &L) {
L = (pNode)malloc(sizeof(Node));
if(!L)
exit(-1);
L->next = L->prior = NULL ;//前驱后继均为空
return ;
}
//====================================================
//遍历
void Traverse(pNode L) {
pNode p = L->next ;
while(p) {
printf("%d ",p->data );
p = p->next ;
}
return ;
}
//======================================================
//====================================================
//只想看看前驱有没有实现
void TraversePrior(pNode L) {
pNode p = L;
if(!L->next) {
return;
}
while(p->next ) {
p = p->next ;//先遍历到最后
}
while(p != L) {//再从最后遍历到最前 真特么的矫情
printf("[%d] ",p->data );
p = p->prior ;
}
return ;
}
//======================================================
//前插法
/* pNew
/
L------L->next
*/
void PreInsert(pNode &L, datatype item) {
pNode pNew = (pNode )malloc(sizeof(Node));
if(!pNew)
exit(-1);
pNew->data = item;
/*插入一个新节点 无非给pNew弄个前驱后继,或者说L的后继变了,
L->next的前驱变了
*/
pNew->next = L->next;
L->next = pNew;
pNew->prior = L;
return;
}
//===========================================================
//尾插法
void TailInsert(pNode &tail, datatype item) {
pNode pNew = (pNode )malloc(sizeof(Node ));
if(!pNew )
exit(-1);
pNew->data = item;
tail->next = pNew;
pNew->prior = tail;
pNew->next = NULL ;
tail = pNew;
return;
}
//==========================================================
//从头开始删
void DeleteNode(pNode &L, datatype &item) {
pNode temp =L->next ;
item = temp->data;//删除的节点的值
temp->next->prior = temp->prior ;//节点删除了,那么她的后继需要一个前驱
temp->prior->next = temp->next ;//她的前驱需要一个后继
free(temp);//释放
temp = NULL ;
return;
}
//===========================================================
//删除链表
void DeleteList(pNode &L) {
if(NULL == L) {
return;
}
pNode p = L->next;
while(p) {
pNode q = p;
// printf("[%d] ",p->data);
p = p->next;
free(q);
q = NULL;
}
/*
if(p)
printf("haha");
else
printf("hehe");
if(L->next )
printf("111111");
else
printf("222222");
这中间部分就是说明p被释放了,但是L->next还是存在的,所以下面那句就是必需
的了。至于为什么L->next还是真我也不是很理解
*/
L->next = NULL;
//free(L);
//L = NULL;算了还是保留头结点吧 看你理解的意思了
return;
}
//=========================================================
int main() {
pNode p;
Init(p);
Traverse(p);
// PreInsert(p,1);
// PreInsert(p,2);
// PreInsert(p,3);
// PreInsert(p,4);
// Traverse(p);
pNode tail = p;
TailInsert(tail,1);
TailInsert(tail,2);
TailInsert(tail,3);
TailInsert(tail,4);//tail永远是尾巴 唉 。。。
Traverse(p);
printf("\n");
printf("遍历前驱:\n");
TraversePrior(p);
printf("\n");
int item;
printf("删除节点:\n");
DeleteNode(p,item);
printf("删除的是%d \n",item);
Traverse(p);
printf("\n");
printf("清空链表:\n");
DeleteList(p);
Traverse(p);
printf("\n");
free(p);
return 0;
}