数据结构 循环单链表和双向链表

循环单链表和普通单链表的代码操作上差别并不大,差别最大的地方在于普通单链表遍历结束的标志是标记指针为空,而循环单链表遍历结束的条件是标记指针不等于头指针。

以下是头文件,其中包括对节点类型额定义,以及循环单链表的函数声明:

#ifndef CLIST_H_
#define CLIST_H_

typedef struct CNode    			/*这个结构体类型用于定义循环单链表的节点*/ 
{
    int iData;
    struct CNode *pNext;
}CNode, *CList;


typedef struct DulNode{              /*这个类型定义用来定义双向链表的节点*/ 
	int data;
	struct DulNode *prior;
	struct DulNode *next;
}DulNode, *DuLinkList;

CNode* BuyNode(int val);
void InitList(CList plist);             //初始化链表
void HeadInsert(CList plist, int val);  //头插法
void TailInsert(CList plist, int val);  //尾插法
bool Delete(CList plist, int key);      //删除
void PrintList(CList plist);            //打印
int  GetLength(CList plist);            //获取链表长度
CNode *Search(CList plist, int key);    //查找
void Traverse(CList plist);             //倒置
void Destroy(CList plist);              //摧毁

#endif

下面是循环单链表的一些操作的具体实现代码:

1. 首先必须有函数来生成一个新的节点,并返回指向它的指针:

          具体的思路是: 先用函数参数接受一个数据i.

                                    再新开辟一个节点,并且把数据i存入节点,

                                     最后把节点的指针返回。

CList BuyNode(int vail){
	/* 这个函数用来申请一个节点,并返回其地址*/ 
	CList i = (CList)malloc(sizeof(CNode));
	i->iData = vail;
	i->pNext = NULL;
	return i;
} 

2. 初始化操作,使得节点收尾相连。

                 思路:  将节点的后继指针指向自己。

void InitList(CList p){
	/* 这个函数是用来初始化列表的,是列表成环*/ 
	if(p == NULL){
		printf("该列表不存在!!");
	}
	p->pNext = p;
}

3. 头插法,不断插入新的节点进入循环单链表。

               思路: 先接受一个数据i和一个链表的头指针。

                          使用数据开辟一个新的节点,

                          将新的节点的后继指针指向头指针的后继指针,

                         将头指针的后继指针指向新节点。

void HeadInsert(CList p, int x){
	/*这个函数用来在循环列表的开头处插入新的节点*/
	if(p == NULL){
		printf("这个循环列表是空的!");
	}
	CList newPlist = BuyNode(x);
	newPlist->pNext = p->pNext;
	p->pNext = newPlist; 
}

4. 尾插法,不断插入新的节点到结尾处。

              思路: 先接收一个数据i,

                         使用数据i创建一个新的节点,

                         用一个新的指针指向头指针的后继指针,并不断循环遍历,

                         遍历到最后一个时停住这个标记指针,

                        将这个标记指针的后继指针指向新节点,

                        再将新节点的后继指针指向头结点,结束。

void TailInsert(CList p, int x){
	/*这个函数用于在循环列表的尾部插入新的节点*/
	if(p == NULL){
		printf("这个循环列表不存在!!");
	} 
	CList newPlist = BuyNode(x);
	CList pRear = p->pNext;
	for(;pRear->pNext != p;pRear = pRear->pNext){
		NULL;
	}
	newPlist->pNext = p;
	pRear->pNext = newPlist;
	pRear = NULL;
}

5. 删除操作,删除掉存有指定数据的节点。

                思路: 使用函数参数接受一个链表头指针p和一个关键数据i,

                            使用一个新的指针作为标记指针指向头结点的后继节点,

                            再使用一个后缀指针跟着标记指针(始终跟在标记指针后面),

                            通过遍历使标记指针指向要删除的目标节点,后缀指针紧随其后。

                            将后缀的指针的后继节点指向标记指针的后继节点,

                            释放标记指针。

void DeletList(CList p, int key){
	/*这个函数用来删除值为key的节点*/
	if(p == NULL){
		printf("这个列表不存在!");
	} 
	CList pPrior = p;
	CList pCur = p->pNext;
	for(;pCur->pNext != p;pCur = pCur->pNext){
		if(pCur->iData == key){
			pPrior->pNext = pCur->pNext;
			free(pCur);
			printf("删除成功!!");
			break;
		}
		pPrior = pCur;
	}
	printf("没有找到要删除的点!!");
}

6. 打印操作,将循环链表内的内容遍历式的打印出来。

                   思路: 函数参数接受一个链表的头指针,

                              使用一个标记指针指向头指针的后继指针,

                             通过遍历的方式打印出每一个节点的数据。

void printList(CList p){
	/* 这个函数是用来打印循环列表的*/
	if(NULL == p){
		printf("该列表不存在,固无法打印!!");
	} 
	CList r = p->pNext;
	int i = 1; 
	for(;r!=p;r=r->pNext){
		printf("第%d个节点的数据是: %d\n",i,r->iData);
		i++;
	}
}

7. 查询操作,用于查找关键数据的节点。

                    思路: 函数参数接收一个数据i,

                               使用一个标记指针指向头结点的后继指针,

                               标记指针不断遍历,

                               当出现符合关键数据的节点时,返回该节点。

CList SearchList(CList plist, int key){
	if(plist == NULL){
		printf("该链表为空白!!");
	}
	CList p_pos = plist->pNext;
	while(p_pos != plist){
		if(p_pos->iData == key){
			printf("查找成功!!");
			return p_pos;
		}
	}
	printf("不存在需要查找的目标节点!!");
}

 ----------------------------------------------------------下面是双向链表 ---------------------------------------------------

普通单链表和双向链表在一些操作上没什么区别,比如查询操作,打印操作,获取节点数据操作,这些操作只需要单方向的进行遍历,所以跟单链表差别不大,而像删除和插入操作,由于引进了前级指针,所以具体的操作上有了一些变化。

以下是双向链表的插入和删除操作:

bool DeletDuNode(DuLinkList p, int i){
	/*该函数使用来删除值为i的节点*/ 
	if(p == NULL){
		printf("该列表不存在!!");
		return false;
	}
	DuLinkList k = p->next;
	for(;k!=NULL;k=k->next){
		if(k->data == i){
			k->prior->next = k->next;
			k->next->prior = k->prior;
			free(k);
			printf("值为i的节点删除成功!!");
			return true;
		}
	}
	printf("删除失败!!");
	return false;
}

bool InsertDuNode(DuLinkList p, int i){
	/*该函数用来插入指定的数字到头部*/	
	if(p == NULL){
		printf("该链表为空!!");
		return false;
	}
	DuLinkList newNode = creatOne(3);
	newNode->prior = p;
	newNode->next = p->next;
	p->next->prior = newNode;
	p->next = newNode;
	printf("节点插入成功!!");
	return true;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值