在任何一本数据结构的书中,都会详细的谈论很多数据结构,比如,线形表,树,图...
而实际项目中,最常用的莫过于数组和链表,以及树(最多的还是二叉树),最近对数据结构复习了一阵,
对链表做一个小结。(以下代码都是C语言实现,由于只是小结,仅对单链表做处理)
链表的基本结构如下:
typedef struct node
{
int data;
struct node* next;
}Node;
其中data是一个Type类型的数据,next是指向下一个Node的一个指针,具体如下图所示
------- ------
| data | | data |
------ ------
| next |----->| next | ----> .....
------- ------
当然,有些时候为了保证链表的通用型,
#define Type int
用Type代替数据的类型,有时候为了想把不同数据都放到一个链表中来,可以考虑把Type 改称 void*,
即
#define Type void *
这样的好处就是,有一个data的指针,可以指向任何类型的数据或者一段内存,当然,对于内存分配,
一定要注意malloc和free(或者用new和delete)
首先我们来看一段代码,计算链表的长度:
下面一段代码是往链表里添加加数据,数据在链表头部加入新数据。
类似往栈里压数据一样。
以下是关于链表的操作的一些代码小结,部分来自网路。
/*
*6.SortedInsert(),给定一个排好序的单链表,在合适的位置插入一个新节点,保证链表的顺序性
*/
void SortedInsert(Node ** headRef,Node * newNode)
{
Node *p=*headRef;
if (p==NULL || newNode->data <= p->data){
newNode->next=p;
*headRef=newNode;
}
else{
while (p->next!=NULL && p->next->data < newNode->data) {
p=p->next;
}
newNode->next=p->next;
p->next=newNode;
}
}
/*
*9.FrontBackSplit(),给定一个链表,和另外两个结点,使这2个节点分别指向链表的头和尾
*/
void FrontBackSplit(Node * source,Node ** frontRef,Node ** backRef)
{
Node *p,*p1;
p=p1=source;
*frontRef=source;
*backRef=NULL;
if (p==NULL||p->next==NULL)
return;
while (p1->next!=NULL){
p1=p1->next;
if (p1->next!=NULL){
p1=p1->next;
p=p->next;
}
}
*backRef=p->next;
p->next=NULL;
}
/*
*10.RemoveDuplicates(),从一个已排序的链表中删除重复的结点
*/
void RemoveDuplicates(Node * head)
{
Node *p1,*p2;
p1=head;
if (p1==NULL||p1->next==NULL)
return;
while(p1->next!=NULL){
if(p1->data==p1->next->data){
p2=p1->next->next;
free(p1->next);
p1->next=p2;
}
else
p1=p1->next;
}
}
/*
*14.SortedMerge(),将两个排好序的链表合成一个有序链表(为递增链表)
*/
Node * SortedMerge(Node * a,Node * b) // 非递归算法
{
Node *result=NULL;
Node **lastPtrRef=&result;//指向新链表的头地址
while (1){
if (a==NULL){
*lastPtrRef=b;
break;
}
else if(b==NULL){
*lastPtrRef=a;
break;
}
if (a->data<=b->data)
MoveNode(lastPtrRef,&a);
else
MoveNode(lastPtrRef,&b);
lastPtrRef=&((*lastPtrRef)->next); //对下一个节点进行处理
}
return result;
}
Node * Recursive SortedMerge(Node * a,Node * b) // 递归合成链表
{
Node *result;
if (a==NULL) return b;
else if (b==NULL) return a;
if (a->data <= b->data){
result=a;
result->next= Recursive SortedMerge(a,b->next);
}
else{
result=b;
result->next= Recursive SortedMerge(a->next,b);
}
return result;
}
而实际项目中,最常用的莫过于数组和链表,以及树(最多的还是二叉树),最近对数据结构复习了一阵,
对链表做一个小结。(以下代码都是C语言实现,由于只是小结,仅对单链表做处理)
链表的基本结构如下:
typedef struct node
{
int data;
struct node* next;
}Node;
其中data是一个Type类型的数据,next是指向下一个Node的一个指针,具体如下图所示
------- ------
| data | | data |
------ ------
| next |----->| next | ----> .....
------- ------
当然,有些时候为了保证链表的通用型,
#define Type int
用Type代替数据的类型,有时候为了想把不同数据都放到一个链表中来,可以考虑把Type 改称 void*,
即
#define Type void *
这样的好处就是,有一个data的指针,可以指向任何类型的数据或者一段内存,当然,对于内存分配,
一定要注意malloc和free(或者用new和delete)
首先我们来看一段代码,计算链表的长度:
int
length(Node
*
head)
{
int i=0; /*统计链表的长度*/
Node *p=head; /*用一个指针指向链表的头*/
if (p==NULL)
return 0;
while (p != NULL){
i++;
p=p->next;
}
return i; /* 返回链表的长度*/
}
{
int i=0; /*统计链表的长度*/
Node *p=head; /*用一个指针指向链表的头*/
if (p==NULL)
return 0;
while (p != NULL){
i++;
p=p->next;
}
return i; /* 返回链表的长度*/
}
下面一段代码是往链表里添加加数据,数据在链表头部加入新数据。
类似往栈里压数据一样。
void
Push(Node
**
headRef,
int
newData)
{
Node *head=*headRef;
Node *pNode=(Node*)malloc(sizeof(Node));
if (!pNode)
return NULL;
pNode->data=newData;
pNode->next=head;
*headRef=pNode;
}
{
Node *head=*headRef;
Node *pNode=(Node*)malloc(sizeof(Node));
if (!pNode)
return NULL;
pNode->data=newData;
pNode->next=head;
*headRef=pNode;
}
以下是关于链表的操作的一些代码小结,部分来自网路。
/*
*1.Count(),给定一个链表,和一个整型的数据,返回在这个链表中这个数据出现的个数
*/
int Count(Node * head, int searchFor)
{
int i=0;
Node *p=head;
if (p==NULL)
return 0;
while(p!=NULL){
if (p->data == searchFor){
i++;
}
p=p->next;
}
return i;
}
*1.Count(),给定一个链表,和一个整型的数据,返回在这个链表中这个数据出现的个数
*/
int Count(Node * head, int searchFor)
{
int i=0;
Node *p=head;
if (p==NULL)
return 0;
while(p!=NULL){
if (p->data == searchFor){
i++;
}
p=p->next;
}
return i;
}
/*
*2.GetNth(),给定一个链表和一个下标n,返回链表中第n个数据
*给定下标的范围是0-(length-1)
*/
int GetNth(Node * head, int index)
{
Node *current=head;
int count=0;
while (current!=NULL){
if (count==index)
return current->data;
count++;
curent=current->next;
}
assert(0); //没有找到合适的元素,则报错
}
*2.GetNth(),给定一个链表和一个下标n,返回链表中第n个数据
*给定下标的范围是0-(length-1)
*/
int GetNth(Node * head, int index)
{
Node *current=head;
int count=0;
while (current!=NULL){
if (count==index)
return current->data;
count++;
curent=current->next;
}
assert(0); //没有找到合适的元素,则报错
}
/*
*3.DeleteList(),删除链表
*/
void DeleteList(Node ** headRef)
{
Node *p=*headRef;
while (p!=NULL){
*headRef=(*headRef)->next;
free(p);
p=*headRef;
}
return;
}
*3.DeleteList(),删除链表
*/
void DeleteList(Node ** headRef)
{
Node *p=*headRef;
while (p!=NULL){
*headRef=(*headRef)->next;
free(p);
p=*headRef;
}
return;
}
/*
*4.Pop(),弹出一个数据,也就是对于非空链表,移出头结点,并返回这个结点的数据
*/
int Pop(Node ** headRef)
{
int data;
Node *p=*headRef;
assert(p!=NULL);
*headRef=p->next;
data=p->data;
free(p);
return data;
}
*4.Pop(),弹出一个数据,也就是对于非空链表,移出头结点,并返回这个结点的数据
*/
int Pop(Node ** headRef)
{
int data;
Node *p=*headRef;
assert(p!=NULL);
*headRef=p->next;
data=p->data;
free(p);
return data;
}
/*
*5.InsertNth(),给定链表,插入的位置以及相应的数据,在链表的该位置插入相应的数据
*/
void InsertNth(Node ** headRef, int index, int data)
{
if (index==0)
Push(headRef,data);
else{
Node *current=*headRef;
int i;
for(i=0;i<index-1;i++) {
assert(current!=NULL); //如果失败,当前的下标太大了
current=current->next;
}
assert(current!=NULL); //检查当前结点是否为空
Push(&(current->next),data); //调用push(),在下一个节点的前面插入数据。
}
}
*5.InsertNth(),给定链表,插入的位置以及相应的数据,在链表的该位置插入相应的数据
*/
void InsertNth(Node ** headRef, int index, int data)
{
if (index==0)
Push(headRef,data);
else{
Node *current=*headRef;
int i;
for(i=0;i<index-1;i++) {
assert(current!=NULL); //如果失败,当前的下标太大了
current=current->next;
}
assert(current!=NULL); //检查当前结点是否为空
Push(&(current->next),data); //调用push(),在下一个节点的前面插入数据。
}
}
/*
*6.SortedInsert(),给定一个排好序的单链表,在合适的位置插入一个新节点,保证链表的顺序性
*/
void SortedInsert(Node ** headRef,Node * newNode)
{
Node *p=*headRef;
if (p==NULL || newNode->data <= p->data){
newNode->next=p;
*headRef=newNode;
}
else{
while (p->next!=NULL && p->next->data < newNode->data) {
p=p->next;
}
newNode->next=p->next;
p->next=newNode;
}
}
/*
*7.InsertSort(),给定一个链表,对链表进行排序,使之成为一个有序的链表
*/
void InsertSort(Node ** headRef)
{
Node *p=*headRef,*NewHead=NULL;
if (p==NULL)
return;
while (p!=NULL) {
SortedInsert(&NewHead,p);
p=p->next;
}
*headRef=NewHead;
}
*7.InsertSort(),给定一个链表,对链表进行排序,使之成为一个有序的链表
*/
void InsertSort(Node ** headRef)
{
Node *p=*headRef,*NewHead=NULL;
if (p==NULL)
return;
while (p!=NULL) {
SortedInsert(&NewHead,p);
p=p->next;
}
*headRef=NewHead;
}
/*
*8.Append(),给定两个链表的头,将两个链表连起来
*/
void Append(Node ** aRef,Node ** bRef)
{
Node *current;
if (*aRef==NULL)
*aRef=*bRef;
else{
current=*aRef;
while (current->next != NULL) {
current=current->next;
}
current->next=*bRef;
}
*bRef=NULL;
}
*8.Append(),给定两个链表的头,将两个链表连起来
*/
void Append(Node ** aRef,Node ** bRef)
{
Node *current;
if (*aRef==NULL)
*aRef=*bRef;
else{
current=*aRef;
while (current->next != NULL) {
current=current->next;
}
current->next=*bRef;
}
*bRef=NULL;
}
/*
*9.FrontBackSplit(),给定一个链表,和另外两个结点,使这2个节点分别指向链表的头和尾
*/
void FrontBackSplit(Node * source,Node ** frontRef,Node ** backRef)
{
Node *p,*p1;
p=p1=source;
*frontRef=source;
*backRef=NULL;
if (p==NULL||p->next==NULL)
return;
while (p1->next!=NULL){
p1=p1->next;
if (p1->next!=NULL){
p1=p1->next;
p=p->next;
}
}
*backRef=p->next;
p->next=NULL;
}
/*
*10.RemoveDuplicates(),从一个已排序的链表中删除重复的结点
*/
void RemoveDuplicates(Node * head)
{
Node *p1,*p2;
p1=head;
if (p1==NULL||p1->next==NULL)
return;
while(p1->next!=NULL){
if(p1->data==p1->next->data){
p2=p1->next->next;
free(p1->next);
p1->next=p2;
}
else
p1=p1->next;
}
}
/*
*11.MoveNode(),两个链表的头节点,把其中的一个链表的头节点移动到另外一个链表的头
*/
void MoveNode(Node ** destRef,Node ** sourceRef)
{
int data;
Node *p=*sourceRef;
if (p==NULL){
sprintf(stderr,"Error!Source list is empty ");
return;
}
*sourceRef=p->next;
p->next=*destRef;
*destRef=p;
}
*11.MoveNode(),两个链表的头节点,把其中的一个链表的头节点移动到另外一个链表的头
*/
void MoveNode(Node ** destRef,Node ** sourceRef)
{
int data;
Node *p=*sourceRef;
if (p==NULL){
sprintf(stderr,"Error!Source list is empty ");
return;
}
*sourceRef=p->next;
p->next=*destRef;
*destRef=p;
}
/*
*12.AlternatingSplit(),将给定的一个链表划分成两个链表,奇数号在一个链表aRef,偶数在bRef
*/
void AlterNatingSplit(Node * source,Node ** aRef,Node ** bRef)
{
Node *a=NULL;
Node *b=NULL;
Node *current=source;
while (current!=NULL){
MoveNode(&a,¤t);
if (current!=NULL){
MoveNode(&b,¤t);
}
}
*aRef=a;
*bRef=b;
}
*12.AlternatingSplit(),将给定的一个链表划分成两个链表,奇数号在一个链表aRef,偶数在bRef
*/
void AlterNatingSplit(Node * source,Node ** aRef,Node ** bRef)
{
Node *a=NULL;
Node *b=NULL;
Node *current=source;
while (current!=NULL){
MoveNode(&a,¤t);
if (current!=NULL){
MoveNode(&b,¤t);
}
}
*aRef=a;
*bRef=b;
}
/*
*13.ShuffleMerge(),将两个链表合成一个链表,返回新链表的头
*/
Node * ShuffleMerge(Node * a,Node * b)
{
Node *pMerg=NULL;
if (a==NULL)
return b;
else if ( b==NULL)
return a;
else{
while (a!=NULL&&b!=NULL){
MoveNode(&pMerg,&a);
pMerg=pMerg->next;
MoveNode(&pMerg,&b);
pMerg=pMerg->next;
}
if (a==NULL)
pMerg=b;
else if(b==NULL)
pMerg=a;
}
return pMerg;
}
/*递归进行合并两个队列 */
Node * Recursive ShuffleMerge(Node * a,Node * b)
{
Node *result;
Node *recur;
if (a==NULL)
return b; //如果链表a为空就返回b
else if(b==NULL)
return a; //如果b为空,返回a
else{
recur= Recursive ShuffleMerge(a->next,b->next);//递归调用每个节点的下一个节点;
result=a; //对两个链表的头节点进行处理
a->next=b;
b->next=recur;
return result;
}
}
*13.ShuffleMerge(),将两个链表合成一个链表,返回新链表的头
*/
Node * ShuffleMerge(Node * a,Node * b)
{
Node *pMerg=NULL;
if (a==NULL)
return b;
else if ( b==NULL)
return a;
else{
while (a!=NULL&&b!=NULL){
MoveNode(&pMerg,&a);
pMerg=pMerg->next;
MoveNode(&pMerg,&b);
pMerg=pMerg->next;
}
if (a==NULL)
pMerg=b;
else if(b==NULL)
pMerg=a;
}
return pMerg;
}
/*递归进行合并两个队列 */
Node * Recursive ShuffleMerge(Node * a,Node * b)
{
Node *result;
Node *recur;
if (a==NULL)
return b; //如果链表a为空就返回b
else if(b==NULL)
return a; //如果b为空,返回a
else{
recur= Recursive ShuffleMerge(a->next,b->next);//递归调用每个节点的下一个节点;
result=a; //对两个链表的头节点进行处理
a->next=b;
b->next=recur;
return result;
}
}
/*
*14.SortedMerge(),将两个排好序的链表合成一个有序链表(为递增链表)
*/
Node * SortedMerge(Node * a,Node * b) // 非递归算法
{
Node *result=NULL;
Node **lastPtrRef=&result;//指向新链表的头地址
while (1){
if (a==NULL){
*lastPtrRef=b;
break;
}
else if(b==NULL){
*lastPtrRef=a;
break;
}
if (a->data<=b->data)
MoveNode(lastPtrRef,&a);
else
MoveNode(lastPtrRef,&b);
lastPtrRef=&((*lastPtrRef)->next); //对下一个节点进行处理
}
return result;
}
Node * Recursive SortedMerge(Node * a,Node * b) // 递归合成链表
{
Node *result;
if (a==NULL) return b;
else if (b==NULL) return a;
if (a->data <= b->data){
result=a;
result->next= Recursive SortedMerge(a,b->next);
}
else{
result=b;
result->next= Recursive SortedMerge(a->next,b);
}
return result;
}
/*
*15.Mergesort(),对链表进行归并排序
*/
void MergeSort(Node ** headRef)
{
Node *p=headRef;
Node **aList,**bList;
if (p==NULL||p->next=NULL)
return;
FrontBAckSplit(p,aList,bList);
MergeSort(aList);
MergeSort(bList);
*headRef=SortedMerge(*aList,*bList);
}
*15.Mergesort(),对链表进行归并排序
*/
void MergeSort(Node ** headRef)
{
Node *p=headRef;
Node **aList,**bList;
if (p==NULL||p->next=NULL)
return;
FrontBAckSplit(p,aList,bList);
MergeSort(aList);
MergeSort(bList);
*headRef=SortedMerge(*aList,*bList);
}
/*16.SortedIntersect()
*给定两个有序的链表,统计两个链表中相同的数据,将相同的元素放到新链表中,并返回
*/
Node * SortedIntersect(Node * a,Node * b)
{
Node *result=NULL;
Node **lastPtrRef=&result;
//先比较两个链表的头,如果其中一个为空,则返回NULL
while (a!=NULL && b!=NULL){
if (a->data==b->data){ //找到一个相同的元素
Push(lastPtrRef,a->data);
lastPtrRef=&((&lastPtrRef)->next);
a=a->next;
b=b->next;
}
else if(a->data < b->data)
a=a->next;
else
b=b->next;
}
return result;
}
*给定两个有序的链表,统计两个链表中相同的数据,将相同的元素放到新链表中,并返回
*/
Node * SortedIntersect(Node * a,Node * b)
{
Node *result=NULL;
Node **lastPtrRef=&result;
//先比较两个链表的头,如果其中一个为空,则返回NULL
while (a!=NULL && b!=NULL){
if (a->data==b->data){ //找到一个相同的元素
Push(lastPtrRef,a->data);
lastPtrRef=&((&lastPtrRef)->next);
a=a->next;
b=b->next;
}
else if(a->data < b->data)
a=a->next;
else
b=b->next;
}
return result;
}
/*
*17.Reverse(),给定一个链表,将其反转,即顺序颠倒
*/
void Reverse(Node ** headRef) // 非递归算法
{
Node *result=NULL;
Node *current=*headRef;
Node *next;
while (current!=NULL){
next=current->next;
current->next=result;
result=current;
current=next;
}
*headRef=result;
}
void RecursiveReverse(Node ** headRef) // 递归算法
{
Node *p=*headRef,*pNext;
if (p==NULL ||p->next=NULL)
return;
pNext=p->next;
RecursiveReverse(&pNext);
p->next->next=p;
p->next=NULL;
*headRef=pNext;
}
*17.Reverse(),给定一个链表,将其反转,即顺序颠倒
*/
void Reverse(Node ** headRef) // 非递归算法
{
Node *result=NULL;
Node *current=*headRef;
Node *next;
while (current!=NULL){
next=current->next;
current->next=result;
result=current;
current=next;
}
*headRef=result;
}
void RecursiveReverse(Node ** headRef) // 递归算法
{
Node *p=*headRef,*pNext;
if (p==NULL ||p->next=NULL)
return;
pNext=p->next;
RecursiveReverse(&pNext);
p->next->next=p;
p->next=NULL;
*headRef=pNext;
}
/*
*18.FindCircle(),判断链表中是否有环.
*思路:运用两个指针,一个快指针,一个慢指针,当快的追上慢的,就表示有环
*/
bool FindCircle(Node * pHead)
{
if(pHead = = NULL || pHead->next = = NULL)//无节点或只有一个节点并且无自环
return false;
if(pHead->next = = pHead)//自环
return true;
Node *pTemp1 = pHead;//step 1
Node *pTemp = pHead->next;//step 2
while(pTemp != pTemp1 && pTemp != NULL && pTemp->next != NULL){
pTemp1 = pTemp1->next;
pTemp = pTemp->next->next;
}
if(pTemp = = pTemp1)
return true;
return false;
}
*18.FindCircle(),判断链表中是否有环.
*思路:运用两个指针,一个快指针,一个慢指针,当快的追上慢的,就表示有环
*/
bool FindCircle(Node * pHead)
{
if(pHead = = NULL || pHead->next = = NULL)//无节点或只有一个节点并且无自环
return false;
if(pHead->next = = pHead)//自环
return true;
Node *pTemp1 = pHead;//step 1
Node *pTemp = pHead->next;//step 2
while(pTemp != pTemp1 && pTemp != NULL && pTemp->next != NULL){
pTemp1 = pTemp1->next;
pTemp = pTemp->next->next;
}
if(pTemp = = pTemp1)
return true;
return false;
}