这一章主要就是实现了一个链表:
第一段程序
int
sll_insert( Node *current, int new_value )
{
Node *previous;
Node *new;
while( current->value < new_value ){/**/
previous = current;
current = current->link;
}
new = (Node *)malloc( sizeof( Node ) );
if( new == NULL )
return FALSE;
new->value = new_value;
new->link = current;
previous->link = new;
return TRUE;
}
错误在于做标记的那一个循环,可能如果一直找到最后没找到,是不是就发生了越界现象。同时,如果我们在第一个结点之前插入一个结点,如何去访问到这个结点,那是很困难的。
所以第二个程序引入了root指针作为形参。
int
sll_insert( Node **rootp, int new_value )
{
Node *current;
Node *previous;
Node *new;
current = *rootp;
previous = NULL;
while( current != NULL && current->value < new_value ){
previous = current;
current = current->link;
}
new = (Node *)malloc( sizeof( Node ) );
if( new == NULL )
return FALSE;
new->value = new_value;
new->link = current;
if( previous == NULL )//判断是不是为第一个结点
*rootp = new;
else
previous->link = new;
return TRUE;
}
于是想到利用双重链表可以链接的特性,去消除这个previous,只要刚开始让链表指向&root,不管链表有没有改变指向,反正后面连上一个new就对了。
int
sll_insert( register Node **linkp, int new_value )
{
register Node *current;
register Node *new;
while( ( current = *linkp ) != NULL &&
current->value < new_value )
linkp = ¤t->link;//让linkp在不值向root的时候去指向该结点链接下一节点的指针,这时候取*就能建立对下面结点的链接
new = (Node *)malloc( sizeof( Node ) );
if( new == NULL )
return FALSE;
new->value = new_value;
new->link = current;
*linkp = new;
return TRUE;
}
二重链表:
写的程序和书上不同,比较要注意的地方就是,if语句里面如果有相同的语句可以往前或者往后提出,只要不对它在if里面之后的动作的结果产生影响。
再次简化就考虑if的条件,然后看看哪些值是和这个条件一样的,就可以从语句中提出。
程序如下
#include <stdio.h>
typedef int valuetype;
struct Node;
struct list
{
Node* head;
Node* last;
};
struct Node{
Node* pre;
Node* next;
valuetype value;
};
void dll_insert(register list* mylist,valuetype new_value);
fuctionn.cpp
#include "linked_list_node.h"
#include <stdio.h>
#include <stdlib.h>
void dll_insert(register list* mylist,valuetype new_value){
register Node* current = mylist->head;
register Node* previous;
while (current!=NULL && current->value <= new_value)
{
if(current->value == new_value)
return;
previous = current;
current = current->next;
}
register Node* newnode = (Node*)malloc(sizeof(Node));
if(newnode == NULL)
{
exit(EXIT_FAILURE);
}
newnode->value = new_value;
newnode->next = current;
if (current != NULL)
{
current->pre = newnode;
if(current == mylist->head)
{
mylist->head = newnode;
newnode->pre = NULL;
}
else
{
previous->next = newnode;
newnode->pre = previous;
}
}
else
{
if (current == mylist->head)
{
newnode->pre = NULL;
mylist->head = newnode;
}
else
{
previous->next = newnode;
newnode->pre = previous;
}
mylist->last = newnode;
}
}
main.cpp
#include "linked_list_node.h"
#include <stdio.h>
#include <stdlib.h>
int main(){
register list* mylist = (list*)malloc(sizeof(list));
if(mylist == NULL)
return EXIT_FAILURE;
mylist->last = mylist->head = NULL;
dll_insert(mylist,1);
dll_insert(mylist,2);
dll_insert(mylist,0);
dll_insert(mylist,4);
dll_insert(mylist,2);
return EXIT_SUCCESS;
}
主要就是判断当前链表是不是为空,这个结点要插在链表的头,尾,还是中间。
课后题:
链表的反转:利用3个指针的不断移动,就可以做到反向连接。
Node* sll_reverse(Node* first){
if(first == NULL)
return NULL;
register Node* pre = NULL;
register Node* cur = first;
register Node* aft = first->next;
for (; aft != NULL; )
{
cur->next = pre;
pre = cur;
cur = aft;
aft = aft->next;
}
cur->next = pre;
return cur;
}
附上单链表的整个源代码:
linked_node.h
#include <stdio.h>
#include <stdlib.h>
typedef int valuetype;
struct Node
{
Node* next;
valuetype value;
};
bool dll_insert(register Node** root,valuetype newvalue);
Node* sll_reverse(Node* first);
int sll_remove(register Node** rootp,register Node* node);
functionn.cpp
#include "linked_node.h"
#include <stdio.h>
#include <stdlib.h>
bool dll_insert(register Node** root,valuetype newvalue){//当root为空的时候把头结点以及从NULL改变到了newnode
register Node* current;
while ((current = *root) != NULL && current->value < newvalue)
{
root = ¤t->next;
}
register Node* newnode = (Node*)malloc(sizeof(Node));
if(newnode == NULL)
{
exit(EXIT_FAILURE);
return false;
}
newnode->value = newvalue;
newnode->next = *root;//或者current
*root = newnode;//即使root没改变是指向头结点的指针的指针,也是成立
return true;
}
Node* sll_reverse(Node* first){
if(first == NULL)
return NULL;
register Node* pre = NULL;
register Node* cur = first;
register Node* aft = first->next;
for (; aft != NULL; )
{
cur->next = pre;
pre = cur;
cur = aft;
aft = aft->next;
}
cur->next = pre;
return cur;
}
int sll_remove(register Node** rootp,register Node* node){
register Node* current;
while ((current = *rootp) != NULL && current != node)
{
rootp = ¤t->next;
}
if(current == NULL)
return false;
*rootp = current->next;
free(node);
return true;
}
#include <stdio.h>
#include "linked_node.h"
#include <stdlib.h>
int main(){
register Node* root = (Node*)malloc(sizeof(Node));
if(root == NULL)
{
exit(EXIT_FAILURE);
return EXIT_FAILURE;
}
root = NULL;
dll_insert(&root,1);
dll_insert(&root,2);
dll_insert(&root,3);//为什么不管怎么插入永远指向头结点
dll_insert(&root,4);
dll_insert(&root,3);
root = sll_reverse(root);
register Node* node = root;
while (node != NULL && node->value != 2)
{
node = node->next;
}
if (node != NULL)
sll_remove(&root,node);
return EXIT_SUCCESS;
}
这里包括了课后题的删除结点和链表反转