文章目录
C和指针第十七章 一些数据结构的问题 笔记
-
Dargon
-
2020/11/05
-
所遇到的的重要的问题
-
教科书 来自:《C And Primer》第十七章
-
前记 :把这些简单的理解先记录在这,等待自己以后再次发现,再次更改或者升级,真好!
1.关于堆栈 Stack
堆栈的特点:先进后出,向上生长,主要的函数时POP and Push函数,实现进栈和出栈的操作
1.1用数组的形式实现
大致的描述,就是申请一个大数组,PUSH的话 就把数组下标向后移动一个(就是+1)操作;POP的话就直接数组向前一个(下标-1)操作
其实一个简单的基本堆栈数组实现思路就是这样:创造、增大、删除、入栈、出栈、栈顶、……
/* Dynamic array stack */
static STACK_TYPE *stack;
static size_t stack_size;
static int top_element =-1;
void create_stack( size_t size ) {
assert( stack_size ==0 );
stack_size =size;
stack =malloc( size *sizeof(stack) );
assert( stack !=NULL );
}
void resize_stack( size_t new_size ) {
assert( new_size >top_element );
stack =(STACK_TYPE *)realloc( stack, new_size *sizeof(STACK_TYPE) );
assert( stack !=NULL );
}
void resize_stack_v2( size_t new_size ) {
STACK_TYPE *old_stack;
int i;
assert( new_size >top_element );
old_stack =stack;
stack =(STACK_TYPE *)malloc( new_size *sizeof(STACK_TYPE) );
assert( stack != NULL );
for( i =0; i <=top_element; i++ ) {
stack[i] =old_stack[i];
}
free(old_stack);
}
void destroy_stack( void ) {
assert( stack_size >0 );
stack_size =0;
free(stack);
stack =NULL;
}
void push( STACK_TYPE value ) {
assert( ! is_full() );
top_element +=1;
stack[top_element] =value;
}
void pop( void ) {
assert( ! is_empty );
top_element -=1;
}
STACK_TYPE top( void ) {
assert( ! is_empty() );
return stack[top_element];
}
int is_empty( void ) {
assert( stack_size >0 );
return top_element ==-1;
}
int is_full( void ) {
assert( stack_size >0 );
return top_element ==stack_size -1;
}
1.2用链表的形式实现
就像一个单链表一样,你想PUSH 一个的话,我就在前面增加一个节点,这样的话就不存在,Created了,我是动态的,来一个增加一个的内存大小,可试想:原来是Stack指向堆栈,现在来一个new_node ,
这是关键思路:
new_node->value =value;
new_node->next =stack;
stack =new_node;
下面是出栈的关键思路:
first_node =stack;
stack =first_node->next;
free(stack);
整体的代码,关于Link-list 基本实现堆栈的思路
typedef struct STACK_NODE {
STACK_TYPE value;
struct STACK_NODE *next;
} StackNode;
static StackNode *stack;
void create_stack( size_t value ) {
}
void destroy_stack( void ) {
while( !is_empty() )
pop();
}
void push( STACK_TYPE value ) {
StackNode *new_node;
new_node =malloc( sizeof(StackNode) );
assert( new_node !=NULL );
new_node->value =value;
new_node->next =stack; //接在前面
stack =new_node;
}
void pop( void ) {
StackNode *first_node;
assert( first_node != NULL );
first_node =stack;
stack =first_node->next;
free(first_node);
}
STACK_TYPE top( void ) {
assert( !is_empty() );
return stack->value;
}
/* justic the list empty, if empty return 1,else return 0
// how to use ,such as assert( !is_empty() );
*/
int is_empty( void ) {
return (stack ==NULL);
}
int is_full( void ) {
return FALSE;
}
2.关于队列 Queue
类似讲一个数组头尾连起来,形成一个圈,分别用front 和rear 指向队列的头和尾巴,insert插入一个的话,将尾巴Rear +1;同样delete 删除一个的话,就直接将front -1就可以了,但是……
在判断空 和 满的时候,会有异样的问题出现:空和满有一个状态是相同的rear 比 front 多1个
解决: 放置一个数组元素不用 。因此出现“假满”
的状况
可以试验
当队列为空的时候,恰好满足 (rear +1) % QUEUE_SIZE == front
当队列为“假满"的时候,满足(rear +2) % QUEUE_SIZE == front
(通过自己简单的举例画一画,你能很清楚地了解到)
2.1用数组实现 Queue
#define QUEUE_SIZE 100
#define ARRAY_SIZE (QUEUE_SIZE +1)
static QUEUE_TYPE queue[ARRAY_SIZE];
static size_t front =1;
static size_t rear =0;
void create_queue( size_t size ) {
}
void destory_queue( void ) {
}
void insert( QUEUE_TYPE value ) {
assert( !is_full_q );
rear =(rear +1) %ARRAY_SIZE;
queue[rear] =value;
}
void delete( void ) {
assert( !is_empty_q );
front =(front +1) %ARRAY_SIZE;
}
QUEUE_TYPE first( void ) {
assert( !is_empty_q() );
return queue[front];
}
int is_empty_q( void ) {
return ( (rear +1) % ARRAY_SIZE == front );
}
int is_full_q( void ) {
return ( (rear +2) & ARRAY_SIZE == front );
}
2.2用链表实现 Queue
用链表link-list 实现的比较有意思
实现insert 的时候,在rear 部插入
实现delete 时候,在front 部删除
typedef struct QUEUE_NODE {
QUEUE_TYPE value;
struct QUEUE_NODE *next;
} QueueNode;
static QueueNode *queue;
static QueueNode *front;
static QueueNode *rear;
void queue_insert( QUEUE_TYPE value ) {
QueueNode *new_node;
new_node =malloc( sizeof(QueueNode) );
assert( new_node != NULL );
new_node->value =value;
new_node->next =NULL;
if( rear ==NULL )
front =new_node;
else
rear->next =new_node; //接在后面
rear =new_node;
}
void delete( void ) {
QueueNode *next_node;
assert( ! is_empty_q() );
next_node =front->next;
free(front);
front =next_node;
if( front ==NULL )
rear =NULL;
}
QUEUE_TYPE first( void ) {
assert( ! is_empty_q() );
return front->value;
}
int is_empty_q( void ) {
return ( front ==NULL );
}
int is_full_q( void ) {
return 0;
}
3.关于树 Tree
3.1简单的二叉搜索树(Binary search tree)BST
二叉搜索树,每个节点至多有两个孩子,left-child和 right-child 其中每个节点比它的左子树所有节点的值都要大
,但比它右子树的所有节点的值都要小
其中最上面的节点问树根 Root 最小面没有节点的为叶子 leaf
3.2用数组实现 BST
整体是在一个大的数组里面,给出一个value 值,进行 insert的时候,在数组中找出value 的位置,直接进行放入即可
难点在于 delete:
要用到递归来实现,如果删除一个节点,找出左子树内最大的值的节点(一直往右子树进行找即可),将其删除,把值给current节点,这样就把节点间接的删除了。若是出现该节点的左子树没有 ,这时候就要找右子树那一串中最小值的节点,删除之后,再把最小值给current。对于最后的递归 其实只调用了一次,找到叶节点 delete之后,把值给current 。
static TREE_TYPE tree[ARRAY_SIZE];
static int left_child( int current ) {
return ( current *2 );
}
static int right_child( int current ) {
return ( current *2 +1 );
}
void insert( TREE_TYPE value ) {
int current;
assert( value !=0 );
current =1; //For index
while( tree[current] != 0 ) {
if( value <tree[current] ) {
current =left_child( current );
}
else {
assert( value != tree[current] );
current =right_child( current );
}
assert( current <ARRAY_SIZE );
}
tree[current] =value;
}
//Delete Function use recrusion//
void delete_tree( TREE_TYPE value ) {
int current;
int left;
int right;
int left_subtree_empty;
int right_subtree_empty;
current =1;
//Seek for the location/place
while( tree[current] !=value ) {
if( value <tree[current] ) {
current =left_child(current);
}
else {
current =right_child(current);
}
assert( current <ARRAY_SIZE );
assert( tree[current] !=0 );
}
//
left =left_child( current );
right =right_child( current );
left_subtree_empty =(( left >ARRAY_SIZE ) || ( tree[left] ==0 ));
right_subtree_empty =( ( right >ARRAY_SIZE) || ( tree[right] ==0 ) );
//For leaf node have no chilenode
if( left_subtree_empty && right_subtree_empty ) {
tree[current] =0;
}
else {
int this_child;
int next_child;
// have left node,so seek for the right biggest value
if( !left_subtree_empty ) {
this_child =left;
next_child =right_child(this_child);
while( next_child <ARRAY_SIZE && tree[next_child] != 0 ) {
this_child =next_child;
next_child =right_child( this_child );
}
}
// have rigth node, so seek for the left smallest value
else {
this_child =right;
next_child =left_child(this_child);
while( next_child <ARRAY_SIZE && tree[next_child] !=0 ) {
this_child =next_child;
next_child =left_child( this_child );
}
}
value =tree[this_child];
// Use recrusion to solve this question 一层一层进行剥开
delete_tree(value);
tree[current] =value;
}
}
TREE_TYPE *find( TREE_TYPE value ) {
int current;
current =1;
while( current <ARRAY_SIZE && tree[current] !=value ) {
if( value <tree[current] ) {
current =left_child( current );
}
else {
current =right_child( current );
}
}
if( current <ARRAY_SIZE )
return (tree +current);
else
return 0;
}
void callback( TREE_TYPE value ) {
printf(" %d ", value);
}
static void do_pre_order_traverse( int current, void (*callback)( TREE_TYPE value ) ) {
if( current <ARRAY_SIZE && tree[current] != 0 ) {
callback(tree[current]);
do_pre_order_traverse( left_child(current), callback );
do_pre_order_traverse( right_child(current), callback );
}
}
void pre_order_traverse( void (*callback)( TREE_TYPE value ) ) {
do_pre_order_traverse( 1, callback );
}
3.3用链表实现 BST
包含一些其他函数 对于递归的调用应该好好理解
static TreeNode *tree;// The Big Tree Root
void insert_v1( TREE_TYPE value ) {
TreeNode *current;
TreeNode **link;
link =&tree;
while( (current =*link) != NULL ) {
if( value <current->value ) {
link =&(current->left);
}
else {
assert( value != current->value );
link =&(current->left);
}
}
current =(TreeNode *)malloc( sizeof(TreeNode) );
assert( current != NULL );
current->value =value;
current->left =current->right =NULL;
*link =current;
}
static void do_destroy_tree(TreeNode *current) {
if( current !=NULL ) {
do_destroy_tree( current->left );
do_destroy_tree( current->right );
free(current);
}
}
void destroy_tree() {
do_destroy_tree( tree );
}
TREE_TYPE *find( TREE_TYPE value ) {
TreeNode *current;
current =tree;
while( current !=NULL && current->value != value ) {
if( value <current->value ) {
current =current->left;
}
else {
current =current->right;
}
}
if( current != NULL ) {
return &(current->value);
}
else {
return NULL;
}
}
void delete_treenode( TREE_TYPE value ) {
TreeNode *current;
TreeNode **link;
link =&tree;
while( (current =*link) !=NULL && current->value !=value ) {
if( value <current->value ) {
link =&(current->left);
}
else {
link =&(current->right);
}
}
assert( current != NULL );
if( current->left ==NULL && current->right ==NULL ) {
*link =NULL;
free(current);
}
else if( current->left ==NULL || current->right ==NULL ) {
if( current->left !=NULL ) {
*link =current->left; //上一个->left 指向当前current->left
}
else {
*link =current->right; //上一个->right 指向当前current->right
}
free (current);
}
else {
TreeNode *this_child;
TreeNode *next_child;
this_child =current->left;
next_child =this_child->right;
while( next_child != NULL ) {
this_child =next_child;
next_child =this_child->right;
}
value =this_child->value;
delete_treenode(value);
current->value =value;
}
}
void callback( TREE_TYPE value ) {
printf(" %d ", value);
}
static void do_pre_order_traverse_v1( TreeNode *current, void(* callback) (TREE_TYPE value) ) {
if( current != NULL ) {
callback( current->value );
do_pre_order_traverse_v1( current->left, callback );
do_pre_order_traverse_v1( current->right, callback );
}
}
static void do_in_order_traverse_v1( TreeNode *current, void(* callback) (TREE_TYPE value) ) {
if(current != NULL) {
do_in_order_traverse_v1( current->left, callback );
callback( current->value );
do_in_order_traverse_v1( current->right, callback );
}
}
static void do_post_order_traverse_v1( TreeNode *current, void(* callback) (TREE_TYPE value) ) {
if(current != NULL) {
do_post_order_traverse_v1( current->left, callback );
do_post_order_traverse_v1( current->right, callback );
callback( current->value );
}
}
void pre_order_traverse_v1( void(* callback)(TREE_TYPE value) ) {
do_pre_order_traverse_v1( tree, callback );
}
int count_nodes( TreeNode *tree ) {
if( tree !=NULL ) return 0;
return (1 +count_nodes(tree->left) +count_nodes(tree->right));
}
int number_of_nodes() {
return count_nodes(tree);
}
int check_bst_subtree( TreeNode *node, int min, int max ) {
if( node ==NULL )
return TRUE;
if( node->value <min && node->value >max )
return FALSE;
if( !(check_bst_subtree(node->left, min, node->value -1)) || //向左边找最大也只能是 (node->value -1) 小的可以很小
!(check_bst_subtree(node->right, node->value +1, max)) );//向右边找最最小也只能是 (node->value +1) 大的可以很大
return FALSE;
return TRUE;
}
int check_bst_tree() {
int min;
int max;
return check_bst_subtree( tree, min, max );
}
4.感悟
C和指针总算是看完了,有很多的点直接指到我之前学C 的时候的容易错乱的地方,发现是更稍微深入的理解 C 的特性,真好!
我认为语言这东西,这些比较基础经典的还是要常常翻一翻的,保持自己脑袋在用就行了,相信后面的学习会有更加不同的体会吧,加油 dargon