您的位置:首页 > 理论基础 > 数据结构算法

数据结构复习之单链表:基本操作及逆序打印、逆转、合并等

2015-08-18 10:07 621 查看
二叉树的定义

#include “stdafx.h”
#include<malloc.h>

struct ListNode;
typedef int ValueType;
typedef struct ListNode* ListNode;

/*
List是指向ListNode结构体首地址的指针,若定义List list,要使用list->value来访问结构体中的变量值,“->”运算符是取指针所指向的值。若定义struct ListNode list,则list只是个struct,访问成员变量value要使用list.value
*/
typedef ListNode List;

//单链表,这里使用的链表没有专门的头节点,头结节点与其他节点一样,存有一个value
struct ListNode
{
ValueType value;
struct ListNode *next;    //VS2010中可省略这一行的struct
};


与上面等价、但更简洁的二叉树定义如下:

typedef struct ListNode
{
ValueType value;
struct ListNode *next;
}*ListNode, *List;


定义好数据结构之后,就可以写各种操作函数了:

void nodeInit(ListNode node, ValueType value, ListNode next)
{
node->value=value;
node->next=next;
}

int listLen(List list)
{
if(list==NULL)
return 0;
int len=1;
ListNode p=list;
while(p->next!=NULL)
{
len++;
p=p->next;
}
return len;
}

//搜索简洁版:返回目标节点
ListNode find1(List list, ValueType val)
{
if(list == NULL)
return NULL;

ListNode p=list;
while(p->next!=NULL && p->value != val)
{
p=p->next;
}
if(p->next == NULL)
return NULL;
return p;
}

//find的另一版本:若找到则返回元素的位置序号(从0开始),否则返回-1
int find2(List list,ValueType theValue)
{
if(list == NULL)
return -1;
ListNode* p;
p=list;

int position=0;
int len=listLen(list);

while(p->next != NULL && p->value != theValue)
{
position++;
p = p->next;
}
if(position+1 ==len && p->value != theValue)
return -1;
return position;
}

//找到pos节点的前驱节点
ListNode findPrev(List list, ListNode node)
{
ValueType val = node->value;
int thePos=find(list,val);     //pos节点的位置
if(list==NULL || thePos == -1 || thePos == 0)
return NULL;

ListNode p = list;
ListNode q = p->next;
while(q != NULL && q->value != val)
{
p = p->next;
q = q->next;
}
return p;  //这是在保证pos节点存在于链表中且不是头节点的情况下才返回的
}

//插入简洁版:在list中node节点后面插入inserted节点
void insert1(List list, ListNode node, ListNode inserted)
{
if(list == NULL || node == NULL || inserted == NULL)
return;

ListNode p = list;
while(p->value != node->value)
{
p = p->next;
}
if(p->value != node->value) //没找到
return;
if(p->next == NULL) //在表尾插入
p->next = inserted;
else
{
inserted->next = p->next;
p->next = inserted;
}
}

//在链表list中下标为position的节点后面插入值value
void insert2(List *listAddr, int position, ValueType value)
{
List newNode = (ListNode )malloc(sizeof(struct ListNode));
if(newNode == NULL)
{
printf("分配内存出错");
return;
}
newNode->value = value;

if(*listAddr == NULL)
{
*listAddr = newNode;
newNode->next = NULL;
return;
}

ListNode temp=*listAddr;

if(position < 0) //这时在链表最前面插入节点
{
*listAddr=newNode;
newNode->next = temp;//(ListNode )temp;
}
else if(position+1 >= listLen(*listAddr))
{
while(temp->next != NULL)
{
temp = temp->next;
}
temp->next = newNode;
newNode->next = NULL;
}
else
{
int i=0;
while(i < position)
{
temp = temp->next;
i++;
}
newNode->next = temp->next;
temp->next = newNode;
}
}

//删除节点
void removeNode(List *list, ValueType value)
{
if(list == NULL || *list == NULL)
return;

ListNode pToBeDeleted = *list;
if((*list)->value == value)
{
*list=(*list)->next;
free(pToBeDeleted);
pToBeDeleted = NULL;
}
else
{
ListNode pre;
while(pToBeDeleted != NULL && pToBeDeleted->value != value)
{
pre=pToBeDeleted;
pToBeDeleted = pToBeDeleted->next;
}
if(pToBeDeleted == NULL)
{
if(pre->value != value)    //value不在链表中
return;
//value位于最后一个节点中
pre->next = NULL;
free(pToBeDeleted);
}
else
{
pre->next = pToBeDeleted->next;
free(pToBeDeleted);
pToBeDeleted = NULL;
}
}

}

//删除链表
void removeList(List list)
{
ListNode p,temp;
p=list;
while(p != NULL)
{
temp=p->next;
free(p);
p=temp;
}
list = NULL;
}

//从尾到首打印节点值,这个方法会改变链表结构,不好
void print(List list)
{
if(list == NULL)
return;
//int len=listLen(list);
ListNode p,pre=NULL;
p=list;

while(p->next != NULL)
{
pre=p;
p = p->next;
}
printf("\n%d",p->value);
free(p);
if(pre != NULL)
pre->next = NULL;
print(list);
}

//上面方法的改进版
void printNodesReversing(List list)
{
if(list == NULL)
return;
if(list->next != NULL)
printNodesReversing(list->next);
printf("%d\n",list->value);
}

//快速删除节点:可在O(1)时间内完成(对于非尾节点)
//可能会对头指针操作,所以list一定要用指向指针的指针!!
void fastDelet(List *list, ListNode toBeDeleted)
{
if(!list || !toBeDeleted)
return;
if(toBeDeleted->next == NULL)      //先处理特殊情况可能代码更容易写出来
{
//特殊情况:list只有一个节点
if(*list == toBeDeleted)
{
free(*list);
*list = NULL;
toBeDeleted =NULL;
return;
}
ListNode p = *list;
ListNode pre = NULL;
while(p->next != NULL)
{
pre = p;
p = p->next;
}
pre->next = NULL;
free(toBeDeleted);
toBeDeleted = NULL;
}
else
{
ListNode next = toBeDeleted->next;
toBeDeleted->value = next->value;
toBeDeleted->next = next->next;
free(next);
}
}

//查找链表的倒数第k(k>=1)个节点
ListNode findK(List list, int k)
{
int len = listLen(list);
if(k < 1 || k > len)
return NULL;
ListNode p1 = list;
ListNode p2 = list;
int count = len;
while(p1->next != NULL)
{
count--;
if(count <= len - k)
{
p2 = p2->next;
}
p1 = p1->next;
}
return p2;
}

//链表逆转
//解法1:从后往前逆转,递归依次找到最后一个节点。时间O(n^2)
void reverseList1(List list, int length, List newList, ListNode lastNode)
{
//if(list == NULL)
//   return;
if(length <= 0)
return;
List reversed;
ListNode p = list;
ListNode pre = NULL;
for(int i = 0; i < length; i++)
{
pre = p;
p = p->next;
}
//if(pre == NULL)  //出口
//  return;
ListNode
newList = p;
newList->next = pre;
lastNode = pre;
reverseList1(list, length-1, newList,lastNode->next);

}

//解法2:从前往后逆转,把断开的地方缓存起来。时间O(n)
List reverseList2(List list)
{
if(list == NULL)
return NULL;
ListNode newHead = NULL;   //逆转之后的新表头
ListNode lastNewHead;      //上一个表头
ListNode p = list;
while(p->next != NULL)
{
lastNewHead = newHead;
newHead = p;
newHead->next = lastNewHead;

p = p->next;
}
lastNewHead = newHead;
newHead = p;
newHead->next = lastNewHead;

return newHead;
}

//合并两个有序链表仍保持有序,这里以升序为例
//方法1:归并排序中有序数组的合并思想,但需要定义好几个指针,比较麻烦,且容易出错
List mergeLists1(List list1, List list2)
{
if(list1 == NULL)
return list2;
if(list2 == NULL)
return list1;

List newList = NULL;
ListNode p1 = list1;
ListNode p2 = list2;
ListNode lastNode = NULL;  //合并的链表尾节点

if(p1->value <= p2->value)
{
newList = p1;
lastNode = p1;
p1 = p1->next;
}
else
{
newList = p2;
lastNode = p2;
p2 = p2->next;
}

while(p1 != NULL && p2 != NULL)
{
ListNode temp = NULL;
if(p1->value <= p2->value)
{
temp = p1->next;
lastNode->next = p1;
p1 = temp;
}
else
{
temp = p2->next;
lastNode->next = p2;
p2 = temp;
}
lastNode = lastNode-> next;
}

if(p1 != NULL)
lastNode->next = p1;
if(p2 != NULL)
lastNode->next = p2;

return newList;
}

//方法2:利用递归,简洁明了
ListNode mergeLists2(List l1, List l2)
{
if(l1 == NULL)
return l2;
if(l2 == NULL)
return l1;

ListNode newList;
ListNode temp;

if(l1->value <= l2->value)
{
temp = l1->next;    //要断开l1,先缓存
newList = l1;
newList->next = mergeLists2(temp, l2);
}
else
{
temp = l2->next;
newList = l2;
newList->next = mergeLists2(l1, temp);
}
return newList;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息