一、链表与数组的 差别
1、逻辑结构 数组必须事先定义固定的长度 不能动态的增减 链表是动态分配内存
2、内存结构 数组从栈中分配空间 链表在堆中
3、数组在内存中顺序存储 链表随机存储 数组訪问效率高 链表插入删除方便
4、数组存在越界问题
定义表头。 为方便操作 表头数据域为空
二、单链表插入 删除
bool insertList(List head, Type x, int index){
Node *p;
p = head;
int j = 1;
while(p->next&& j < index){
p = p->next;
++j;
}
if(p==NULL) return ERROR;
Node *tmp = (Node *)malloc(sizeof(Node));
tmp->data = x;
tmp->next = p->next; //tmp的后继指向原index位置的结点
p-next = tmp; //p的后继为新结点
return OK;
}
bool deleteList(List head, int index){
Node *p = head;
int j = 1;
while(p->next!=NULL&&j < i){
p = p->next;
++j;
}// p->next为第index个
if(p==NULL || p->next==NULL || j > i) return ERROR; //i可能为负值
Node *tmp = p->next; //tmp指向第index个
p->next = tmp->next; //第index+1个取代index
free(tmp);//释放空间
return OK;
}
三、找出单链表中的倒数第k个元素
解题思路
1、先遍历一遍 计算长度。 再找出后k个
2、双路齐下 p1从第一位開始。p2从第k为開始遍历 直到p2走到头
思路2代码:
Node* find(Node* head, int index){
Node *p1,*p2;
p1 = head;
p2 = head;
for(int i = 0; i < index; i++){
p2 = p2->next; //p2向后移k位
}
while(p2!=NULL){
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
四、单链表反转
解题思路:每次操作结点时 标注其前结点 后结点 对其进行操作
Node* reverse(Node *head){
Node *prev = NULL;
Node *pCur = head;
Node *rHead = NULL;
while(pCur!=NULL){
Node *pNext = head->next;
if(pNext == NULL)
rHead = pCur;
pCur->next = prev; //改变顺序 当前结点指向 自己的前一个结点
prev = pCur; //当前结点变为前结点 (为了下一个结点准备)
pCur = pNext; //结点后移
}
}
五、从尾到头输出单链表
1、递归输出
2、非递归输出
非递归操作 :
1).能够使用 “四” 的代码进行反转 然后输出
2).遍历结点入栈 然后输出
六、寻找单链表的中间结点
1、遍历求长度length 然后再遍历输出
2、双路齐下 p1走一步 p2走两步 p2走到终点时 p1正好到中点
Node* findMiddle(Node *head){
Node *p1 = head;
Node *p2 = head;
while(p2->next->next!=NULL){
p2 = p2->next->next;
p1 = p1->next;
}
return p1;
}
七、单链表排序
与数组排序差别不大,交换元素时 仅仅交换数据域的内容就好。链表的顺序结构不用变化
八、单链表中随意 交换两个元素 (要注意表头)
将2个结点进行交换 要注意 next指针的 交换问题
//将p q结点交换
Node* swap(Node* head,Node* p,Node* q){
if(head==NULL || p==NULL || q==NULL){
Print(ERROR);
return head;
}
if(p==q){
Print(OK);
return head;
}
else if(p->next == q){ //两节点相邻
Node* prev = getPrev(p);
p->next = q->next;
q->next = p;
prev->next = q;
}
else if(q->next == p){
Node* prev = getPrev(q);
q->next = p->next;
p->next = q;
prev->next = p;
}
else if(p!=q){ //两节点不相邻 且不同 交换前后指针域
Node* prev1 = getPrev(p);
Node* prev2 = getPrev(q);
Node* next1 = p->next;
Node* next2 = q->next;
p->next = next2;
prev2->next = p;
q->next = next1;
prev1->next = q;
}
return head;
}
九、检測一个较大的单链表是否有环
双路齐下法 一个走一步一个走2步 看是否会相遇
十、推断两个(无环)单链表是否交叉
推断最后一个结点是否同样
十一、删除单链表中的反复结点
哈希, 建议一hash_map ,遍历链表 若结点出现反复则删除
十二、合并两个有序链表(非交叉)
1、递归
Node* Merge(Node* head1, Node* head2){
if(head1==NULL)
return head2;
if(head2==NULL)
return head1;
Node* head=NULL;
if(head1->data < head2->data){
head = head1;
head->next = Merge(head1, head2);
}else {
head = head2;
head->next = Merge(head1, head2);
}
return head;
}
2、非递归
Node* Merge(Node*head , Node* head1, Node* head2){
Node* tmp = head;
while(head1!=NULL&&head2!=NULL){
if(head1->data < head2->data){
tmp->next = head1;//指向head1当前结点
tmp = head1;//移动tmp的位置
head1 = head1->next;//head1后移
}else {
tmp->next = head2;
tmp = head2;
head2= head2->next;
}
}
if(head1==NULL)
tmp->next = head2;
if(head2==NULL)
tmp->next = head1;
return head;
}
1、逻辑结构 数组必须事先定义固定的长度 不能动态的增减 链表是动态分配内存
2、内存结构 数组从栈中分配空间 链表在堆中
3、数组在内存中顺序存储 链表随机存储 数组訪问效率高 链表插入删除方便
4、数组存在越界问题
定义表头。 为方便操作 表头数据域为空
二、单链表插入 删除
bool insertList(List head, Type x, int index){
Node *p;
p = head;
int j = 1;
while(p->next&& j < index){
p = p->next;
++j;
}
if(p==NULL) return ERROR;
Node *tmp = (Node *)malloc(sizeof(Node));
tmp->data = x;
tmp->next = p->next; //tmp的后继指向原index位置的结点
p-next = tmp; //p的后继为新结点
return OK;
}
bool deleteList(List head, int index){
Node *p = head;
int j = 1;
while(p->next!=NULL&&j < i){
p = p->next;
++j;
}// p->next为第index个
if(p==NULL || p->next==NULL || j > i) return ERROR; //i可能为负值
Node *tmp = p->next; //tmp指向第index个
p->next = tmp->next; //第index+1个取代index
free(tmp);//释放空间
return OK;
}
三、找出单链表中的倒数第k个元素
解题思路
1、先遍历一遍 计算长度。 再找出后k个
2、双路齐下 p1从第一位開始。p2从第k为開始遍历 直到p2走到头
思路2代码:
Node* find(Node* head, int index){
Node *p1,*p2;
p1 = head;
p2 = head;
for(int i = 0; i < index; i++){
p2 = p2->next; //p2向后移k位
}
while(p2!=NULL){
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
四、单链表反转
解题思路:每次操作结点时 标注其前结点 后结点 对其进行操作
Node* reverse(Node *head){
Node *prev = NULL;
Node *pCur = head;
Node *rHead = NULL;
while(pCur!=NULL){
Node *pNext = head->next;
if(pNext == NULL)
rHead = pCur;
pCur->next = prev; //改变顺序 当前结点指向 自己的前一个结点
prev = pCur; //当前结点变为前结点 (为了下一个结点准备)
pCur = pNext; //结点后移
}
}
五、从尾到头输出单链表
1、递归输出
2、非递归输出
非递归操作 :
1).能够使用 “四” 的代码进行反转 然后输出
2).遍历结点入栈 然后输出
六、寻找单链表的中间结点
1、遍历求长度length 然后再遍历输出
2、双路齐下 p1走一步 p2走两步 p2走到终点时 p1正好到中点
Node* findMiddle(Node *head){
Node *p1 = head;
Node *p2 = head;
while(p2->next->next!=NULL){
p2 = p2->next->next;
p1 = p1->next;
}
return p1;
}
七、单链表排序
与数组排序差别不大,交换元素时 仅仅交换数据域的内容就好。链表的顺序结构不用变化
八、单链表中随意 交换两个元素 (要注意表头)
将2个结点进行交换 要注意 next指针的 交换问题
//将p q结点交换
Node* swap(Node* head,Node* p,Node* q){
if(head==NULL || p==NULL || q==NULL){
Print(ERROR);
return head;
}
if(p==q){
Print(OK);
return head;
}
else if(p->next == q){ //两节点相邻
Node* prev = getPrev(p);
p->next = q->next;
q->next = p;
prev->next = q;
}
else if(q->next == p){
Node* prev = getPrev(q);
q->next = p->next;
p->next = q;
prev->next = p;
}
else if(p!=q){ //两节点不相邻 且不同 交换前后指针域
Node* prev1 = getPrev(p);
Node* prev2 = getPrev(q);
Node* next1 = p->next;
Node* next2 = q->next;
p->next = next2;
prev2->next = p;
q->next = next1;
prev1->next = q;
}
return head;
}
九、检測一个较大的单链表是否有环
双路齐下法 一个走一步一个走2步 看是否会相遇
十、推断两个(无环)单链表是否交叉
推断最后一个结点是否同样
十一、删除单链表中的反复结点
哈希, 建议一hash_map ,遍历链表 若结点出现反复则删除
十二、合并两个有序链表(非交叉)
1、递归
Node* Merge(Node* head1, Node* head2){
if(head1==NULL)
return head2;
if(head2==NULL)
return head1;
Node* head=NULL;
if(head1->data < head2->data){
head = head1;
head->next = Merge(head1, head2);
}else {
head = head2;
head->next = Merge(head1, head2);
}
return head;
}
2、非递归
Node* Merge(Node*head , Node* head1, Node* head2){
Node* tmp = head;
while(head1!=NULL&&head2!=NULL){
if(head1->data < head2->data){
tmp->next = head1;//指向head1当前结点
tmp = head1;//移动tmp的位置
head1 = head1->next;//head1后移
}else {
tmp->next = head2;
tmp = head2;
head2= head2->next;
}
}
if(head1==NULL)
tmp->next = head2;
if(head2==NULL)
tmp->next = head1;
return head;
}